嵌入式Linux的网络连接管理

连接管理器(ConnMan)是一个连接管理守护进程 , 用于管理运行 Linux 操作系统中设备的互联网连接。 它以快速、连贯、同步的方式对不断变化的网络条件提供了低内存消耗。

ConnMan拥有各种插件, 是一个完全模块化的系统, 可以扩展支持各种有线或无线技术,允许对各种用例进行简单的适配和修改。 例如DHCP 和DNS 这样的配置方法就是使用插件实现的。所有的应用程序都使用 D-Bus 来与 ConnMan 通信,与嵌入式 Yocto 构建系统一起使用, 是 GENIVI 规范的一部分。

ConnMan遵循 GPL v2.0许可, 英特尔是该项目的主要贡献者。其内部架构如下:

图1

功能特性

以下特性嵌入到ConnMan中:

  • 通用插件基础结构
  • 设备和网络抽象(带有基本存储支持)
  • IPv4, IPv4-LL (link-local) 和DHCP以及IPv6, DHCPv6,V6到V4的 隧道等
  • 高级路由和 DNS 配置
  • 内置 DNS 代理和智能缓存
  • 内置的 WISPr 热点登录和门户检测
  • 时区配置(手动和自动的 NTP)
  • 代理处理(手动和自动的WPAD)
  • 网络支持(USB, 蓝牙和 WiFi AP 模式)
  • 详细统计处理(家居及漫游)

可以启用各种插件来支持网络:

  • 以太网插件
  • Wifi 插件 WEP40 / WEP128及 WPA/WPA2(个人及企业)
  • 蓝牙插件(使用 BlueZ)
  • 2g / 3g / 4g 插件(使用 oFono)

还提供了附加功能的插件:

  • 回路接口设置
  • PACrunner 代理
  • PolicyKit 授权工具

D-Bus接口

应用程序都使用 D-Bus 来与 ConnMan 通信,通过管理器对象来实现应用入口。管理器对象包含服务对象的引用(接口),其他接口包括 VPN、时钟、任务、技术、会话、通知、对等、代理和计数器等。

图2

D-Bus Manager 接口

D-Bus Manager 解释了所有的方法和属性。

图3

检索所有全局属性的简单方法如下:

bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("net.connman", "/"), "net.connman.Manager")
properties = manager.GetProperties() 

改变一个全局属性也非常简单。 例如, 启用所谓的飞行模式(AKA flight mode)可以以设置该属性: manager.SetProperty ("OfflineMode", dbus.Boolean (1))。

图4

服务接口

高级用户接口易于访问网络细节和用户选择的偏好。 这是服务列表和接口(图5), 以一个单一的平面和排序列表来维护所有可用的服务。

图5

图6

服务状态

图7

  1. 每个服务的基本状态都是"空闲",这意味着这项服务目前根本没有使用。 它也不是试图连接或做任何其他事情。
  2. "关联"状态表明该服务试图建立与网络的低级连接 — 例如, 与 WiFi 接入点相关联/连接。

    3. 在"配置"状态下, 表示服务正在尝试检索/配置 IP 设置。

  3. "准备好"状态标志着一个成功连接的设备,并不意味着它有默认的路由, 但是基本的 IP操作将会成功。

    5. "断开"状态,表明服务将终止当前连接并返回到"空闲"状态。

  4. "失败"状态表明一种错误的行为,类似于"空闲"状态, 服务没有连接。

服务的使用

下面是如何获得一个服务对象:

service = dbus.Interface(bus.get_object("net.connman", path), "net.connman.Service") 

它还包含连接或断开特定服务的方法,ConnMan可以根据策略或通过外部事件(如在以太网电缆中插入)自动连接服务。

图8

图9

技能接口

基本的设备配置任务是通过技能接口完成的,例如, 通过技术接口来切换设备(例如通过 RFKILL)。

图10

用户可以通过 OfflineMode 属性激活离线(飞行)模式。 在离线模式下, 包括以太网在内的所有技能都被关闭。 在离线模式下, 用户可以通过使用 rfkill 命令来临时激活单个技能。

ConnMan 的一些细节

可以通过命令行参数来启动ConnMan:

-c, --config=FILE             Load the specified configuration file instead of /usr/local/etc/connman/main.conf
-d, --debug=DEBUG             Specify debug options to enable
-i, --device=DEV              Specify networking device or interface
-I, --nodevice=DEV            Specify networking interface to ignore
-p, --plugin=NAME,...         Specify plugins to load
-P, --noplugin=NAME,...       Specify plugins not to load
-W, --wifi=NAME               Specify driver for WiFi/Supplicant
-n, --nodaemon                Don't fork daemon to background
-r, --nodnsproxy              Don't enable DNS Proxy
--nobacktrace                 Don't print out backtrace information 

使用示例如下:

connmand -i wlan0 -I eth0 --nodnsproxy --nodaemon >& connman.log 

主配置文件(main.conf)如下:

InputRequestTimeout = 120 (default)---------> input request ( ex. passphrase) timeout
BrowserLaunchTimeout = 300 ( default) -----> The request for launching a browser for portal pages
BackgroundScanning = true --------------------> option for background scanning
FallbackTimeservers = --------------------------> List of fallback timeservers ( used by NTP sync) separated by ","
FallbackNameservers = -------------------------> List of fallback nameservers
DefaultAutoConnectTechnologies = -----------> List of technologies that are marked autoconnectable by default.
PreferredTechnologies = ------------------------> List of preferred technologies from - most preferred one to least preferred
NetworkInterfaceBlacklist = vmnet,vboxnet,virbr,ifb,ve-,vb-   ---> List of blacklisted network interfaces 
AllowHostnameUpdates = true -----------------> Allow connman to change the system hostname ( ex. dhcp hostname option)
SingleConnectedTechnology = false -----------> Keep only a single connected technology at any time
TetheringTechnologies = wifi,bluetooth,gadget
PersistentTetheringMode = false --------------> Restore earlier tethering status when returning from offline mode
Enable6to4 = false ------------------------------> Automatically enable Anycast 6to4 if possible (not recommended. see RFC6343 )
EnableOnlineCheck = false --------------------> Enable use of http get as on online status check
AlwaysConnectedTechnologies = -------------> List of technologies with AutoConnect = true which are always connected regardless of PreferredTechnologies setting 

ConnMan 使用配置文件来提供现有的服务,在 /var/lib/Connman/目录下 。 配置文件名不能包含字母或数字以外的其他字符, 并且必须有一个 Config后缀. 例如:

Ex.      #cat /var/lib/connman/example.config
[global]
Name = Example
Description = Example network configuration
[service_home_ethernet]
Type = ethernet
IPv4 = 192.168.1.42/255.255.255.0/192.168.1.1
IPv6 = 2001:db8::42/64/2001:db8::1
MAC = 01:02:03:04:05:06
Nameservers = 10.2.3.4,192.168.1.99
SearchDomains = my.home,isp.net
Timeservers = 10.172.2.1,ntp.my.isp.net
Domain = my.home
[service_home_wifi]
Type = wifi
Name = my_home_wifi
Passphrase = secret
IPv4 = 192.168.2.2/255.255.255.0/192.168.2.1
MAC = 06:05:04:03:02:01 

设置和配置文件是为用户经常连接的网络而自动创建的,例如:

# cat /var/lib/connman/settings 
[global]
OfflineMode=false

[WiFi]
Enable=true
Tethering=false

[Bluetooth]
Enable=false
Tethering=false 

Vpn 设置可以在 /var/lib/connman-VPN/ 。

写一个插件

基本插件包含通过 CONNMAN 定义的插件描述, 以及通过该描述定义的 init / exit 回调。例如:

#include <connman>
static int example_init(void)
{
    return 0;
}
static void example_exit(void)
{
}
CONNMAN_PLUGIN_DEFINE(example, "Example plugin", CONNMAN_VERSION,
                        example_init, example_exit) 
</connman>

插件通过技术、网络和设备以及其他基础结构与ConnMan的核心功能相互作用。 以下是技术基础设施:

ex. bluetooth plugin
    static struct connman_technology_driver tech_driver = {
        .name           = "bluetooth",
        .type           = CONNMAN_SERVICE_TYPE_BLUETOOTH,
        .probe          = bluetooth_tech_probe,
        .remove         = bluetooth_tech_remove,
        .set_tethering  = bluetooth_tech_set_tethering,
    }; 

为了让连接管理器了解新的插件, 需要通过调用ConnMan驱动注册器来注册它的驱动程序。

connman_technology_driver_register(&tech_driver); 

设备

设备代表给定技术的真实设备,每种技术都可能有很多设备。

static struct connman_device_driver device_driver = {
        .name           = "bluetooth",
        .type           = CONNMAN_DEVICE_TYPE_BLUETOOTH,
        .probe          = bluetooth_device_probe,
        .remove         = bluetooth_device_remove,
        .enable         = bluetooth_device_enable,
        .disable        = bluetooth_device_disable,
    }; 

注册驱动程序:

connman_device_driver_register(&device_driver); 

此外, 需要为每个插件编写处理新设备的检测代码; 蓝牙插件通过为 BlueZ-d-bus 接口来注册观察者来实现。 一旦新的蓝牙设备出现, 插件需要通过调用 ConnMan 设备创建来通知 ConnMan 内涵。 对于蓝牙插件, 这个调用将是:

struct connman_device *device;
device = connman_device_create("bluetooth", CONNMAN_DEVICE_TYPE_BLUETOOTH) 

网络

连接管理器为插件提供了一种手段, 用于处理为每种技术建立 / 处理连接的细节。 对于蓝牙插件, 需要注册一个connmannetworkdriver:

static struct connman_network_driver network_driver = {
        .name           = "bluetooth",
        .type           = CONNMAN_NETWORK_TYPE_BLUETOOTH_PAN,
        .probe          = bluetooth_pan_probe,
        .remove         = bluetooth_pan_remove,
        .connect        = bluetooth_pan_connect,
        .disconnect     = bluetooth_pan_disconnect,
    }; 

然后, 调用注册函数:

connman_network_driver_register(&network_driver); 

源文件的结构解读

初始化函数将在 src/main.c 中在运行主循环之前调用。

src/util.c - /dev/urandom support
src/inotify.c - used by the core (config.c) and the session policy plugin
src/technology.c – used for technology interface
src/notifier.c – basic notifier infrastructure
src/agent.c – agent interface
src/service.c – used for service interface
src/peer_service.c – p2p peer service API
src/peer.c – p2p peer object’s core logic
src/provider.c – provider infrastructure
src/network.c – network infrastructure used by plug-ins
src/config.c – framework for configuration files
src/device.c – device infrastructure used by plug-ins
src/iptables.c – iptables support (netfilter chains and rules)
src/firewall-iptables.c, nftables.c (older firewall.c) – firewall infrastructure.
src/nat.c – used for NAT
src/tethering.c  – tethering infrastructure
src/manager.c – Manager interface
src/stats.c – used for storing service stats ( mmaped into memory)
src/ipconfig.c – IP configuration framework
src/rtnl.c – netlink support
src/session.c – Allows 3rd party applications to request a network session 
src/resolver.c – resolver framework
src/dhcp.c, dhcpv6.c – dhcp framework
src/rfkill.c – rfkill interface support
src/machine.c -  basic systemd-hostnamed ( machine-type- “chassis”) support 

命令行客户端

ConnMan有一个标准的命令行客户端 connmanctl。 它可以有两种运行模式:

  • 在命令行模式中, 命令输入作为对 connmanctl 命令的参数, 就像 systemctl 一样
  • 交互式模式是在没有参数的情况下键入 connmanctl 来开始的。 将改变为 connmanctl 表示它正在等待用户命令, 就像 python 交互模式一样

connmanctl示例:

1.启用和禁用 WiFi

    $ connmanctl technologies - check for the line that says Powered: True/False. 
    $ connmanctl enable wifi - To power the wifi on.
    $ connmanctl disable wifi – To power off the wifi. 

2.连接到一个开放的访问点

本示例的命令显示如何在命令行模式下运行控制器。 为了扫描网络, connmanctl 接受简单的技术名参数。 扫描附近的 WiFi 网络:

$ connmanctl scan wifi To list the available networks found after a scan run (example output): 
$ connmanctl services 
*AO MyNetwork wifi_dc85de828967_68756773616d_managed_psk OtherNET wifi_dc85de828967_38303944616e69656c73_managed_psk AnotherOne wifi_dc85de828967_3257495245363836_managed_wep FourthNetwork wifi_dc85de828967_4d7572706879_managed_wep AnO6penNetwork wifi_dc85de828967_4d6568657272696e_managed_none 
$ connmanctl connect wifi_dc85de828967_4d6568657272696e_managed_none 

3.连接到受保护的AP

对于受保护的AP, 提供一些信息给 ConnMan 守护进程, 例如一个密码。

$ connmanctl
connmanctl> scan wifi ----- To list services: 
connmanctl> services 
connmanctl> agent on --- register the agent to handle user requests.
connmanctl> connect wifi_dc85de828967_38303944616e69656c73_managed_psk  

代理需要根据所连接的网络类型提供更多信息,代理还将打印关于它所需要信息的额外数据, 如下面的示例所示。

Agent RequestInput wifi_dc85de828967_38303944616e69656c73_managed_psk Passphrase = [ Type=psk, Requirement=mandatory ] Passphrase? 

提供完请求的信息后, 然后键入 quit 退出。如果提供的信息是正确的, 那现在应该就连接到受保护的AP了。

各种硬件接口被在ConnMan中称为技术,要列出可用的技术, 可以运行:

$ connmanctl technologies 

那些技术可以通过以下方式进行:

$ connmanctl enable technology_type
$ connmanctl disable technology_type  

例如, 切换 WiFi:

$ connmanctl disable wifi 

测试与调试

ConnMan同时也提供了基于 python 的测试脚本(ex. test-connman, list-services 等)。 通过这些脚本支持连接、断开、自动连接、服务、扫描、启用、禁用、非线性、状态等基本操作。

可以使用-d 命令行选项在 ConnMan 中激活调试打印。

-d Activate all normal debug prints 
-d src/service.c This prints debugging info from src/service.c file only
-d src/network.c:src/ipconfig.c This activates debug prints in src/network.c and src/ipconfig.c files. 
-d 'src/n*.c' This would activate debug print from all the C source files starting with letter 'n' in src directory. Note the quotation marks around option, that is to prevent shell expansion. 
-d '*/n*.c:*/i*.c' Activate debug prints for all C source files starting with letters 'n' or 'i' in any sub-directory.  

Connman 的一些组件有基于环境变量启动的调试版本。 如果环境变量已设置, 则相应组件将打印一些额外的调试信息。可以使用下列环境变量:

* CONNMAN_DHCP_DEBUG: Dhcpv4相关调试信息
* CONNMAN_DHCPV6_DEBUG:  DHCPv6相关调试信息
* CONNMAN_IPTABLES_DEBUG: 使用 iptables 时的额外信息
* CONNMAN_RESOLV_DEBUG: 名称解析器调试打印。 这些调试信息用于当 ConnMan 解析主机名称以供自己使用。 请注意, DNS 代理调试版本不使用此环境变量。 为此, 我们可以使用"-d src / dnsproxy。 "c"命令行选项
* CONNMAN_SUPPLICANT_DEBUG :调试打印, 用于控制和 wpa 拼接过程之间的通信
* CONNMAN_WEB_DEBUG: 当 ConnMan 在 Wispr 进行互联网连接检查时的调试信息 

例如:

CONNMAN_SUPPLICANT_DEBUG=1 src/connmand -n 

译自 http://www.embedded-computing.com/dev-tools-and-os/the-connman

3