网络编程中一些小函数,getifaddrs()等
#include <stdio.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <string.h> #include <net/if.h> #include <net/if_arp.h> #include <arpa/inet.h> #include <errno.h> typedef long LONG; typedef char CHAR; #define CONST const #ifndef SUCCESS #define SUCCESS 0 #endif #ifndef FAIL #define FAIL -1 #endif LONG GetMac(CONST CHAR *pcIfName, CHAR *pcMac) { if (NULL == pcIfName || NULL == pcMac) { printf("NULL == pcIfName || NULL == pcMac\n"); return FAIL; } LONG lFd = 0, lRet = FAIL; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, pcIfName); lFd = socket(AF_INET, SOCK_STREAM, 0); if(lFd < 0) { printf("socket fail\n"); return FAIL; } //lRet = ioctl(lFd, SIOCGIFHWADDR, &ifr, sizeof(ifr)); lRet = ioctl(lFd, SIOCGIFHWADDR, &ifr); if(0 == lRet) { memcpy(pcMac, ifr.ifr_hwaddr.sa_data, 6); printf("\nifr.ifr_hwaddr.sa_data is %s \n",ifr.ifr_hwaddr.sa_data); close(lFd); return SUCCESS; } else { printf("ioctl fail\n"); close(lFd); return FAIL; } } LONG GetIp(CONST CHAR *pcIfName, CHAR *pcIp) { if (NULL == pcIfName || NULL == pcIp) { printf("NULL == pcIfName || NULL == pcIp\n"); return FAIL; } LONG lFd = 0, lRet = FAIL; struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, pcIfName); lFd = socket(AF_INET, SOCK_STREAM, 0); if(lFd < 0) { printf("socket fail\n"); return FAIL; } lRet = ioctl(lFd, SIOCGIFADDR, &ifr); if(0 == lRet) { strncpy(pcIp,inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr),16); close(lFd); return SUCCESS; } else { printf("ioctl fail\n"); close(lFd); return FAIL; } } int main() { LONG lRet = FAIL; CHAR szMac[6] = {0}; CHAR szIp[16] = {0}; CHAR szID[21] = {0}; int i=0; int ulLen = 0; lRet = GetMac("eth0", szMac); for(i = 0; i < sizeof(szMac); i++) { //sprintf(szID + strlen((const char*)szID), "%02X", szMac[i]); //ulLen = snprintf(szID, 1024, "%02X", szMac[i]); //ulLen +=snprintf((szID + ulLen), 1024, "%02X", szMac[i]); printf("%0x,",szMac[i]); } printf("\nlRet is %d,mac is %s\n",lRet,szID); lRet = GetIp("eth0", szIp); printf("lRet is %d,szIp is %s\n",lRet,szIp); return 0; }
getifaddrs()和struct ifaddrs的使用,获取本机IP
http://canlynet.iteye.com/blog/1440054
ifaddrs结构体定义如下:
struct ifaddrs { struct ifaddrs *ifa_next; /* Next item in list */ char *ifa_name; /* Name of interface */ unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */ struct sockaddr *ifa_addr; /* Address of interface */ struct sockaddr *ifa_netmask; /* Netmask of interface */ union { struct sockaddr *ifu_broadaddr; /* Broadcast address of interface */ struct sockaddr *ifu_dstaddr; /* Point-to-point destination address */ } ifa_ifu; #define ifa_broadaddr ifa_ifu.ifu_broadaddr #define ifa_dstaddr ifa_ifu.ifu_dstaddr void *ifa_data; /* Address-specific data */ };
ifa_next指向链表的下一个成员;ifa_name是接口名称,以0结 尾的字符串,比如eth0,lo;ifa_flags是接口的标识位(比如当IFF_BROADCAST或IFF_POINTOPOINT设置到此标识位 时,影响联合体变量ifu_broadaddr存储广播地址或ifu_dstaddr记录点对点地址);ifa_netmask存储该接口的子网掩码;结 构体变量存储广播地址或点对点地址(见括弧介绍ifa_flags);ifa_data存储了该接口协议族的特殊信息,它通常是NULL(一般不关注 他)。
函数getifaddrs(int getifaddrs (struct ifaddrs **__ifap))获取本地网络接口信息,将之存储于链表中,链表头结点指针存储于__ifap中带回,函数执行成功返回0,失败返回-1,且为errno赋值。
很显然,函数getifaddrs用于获取本机接口信息,比如最典型的获取本机IP地址。
/* Standard interface flags. */
enum
{
IFF_UP = 0x1, /* Interface is up. */
# define IFF_UP IFF_UP
IFF_BROADCAST = 0x2, /* Broadcast address valid. */
# define IFF_BROADCAST IFF_BROADCAST
IFF_DEBUG = 0x4, /* Turn on debugging. */
# define IFF_DEBUG IFF_DEBUG
IFF_LOOPBACK = 0x8, /* Is a loopback net. */
# define IFF_LOOPBACK IFF_LOOPBACK
IFF_POINTOPOINT = 0x10, /* Interface is point-to-point link. */
# define IFF_POINTOPOINT IFF_POINTOPOINT
IFF_NOTRAILERS = 0x20, /* Avoid use of trailers. */
# define IFF_NOTRAILERS IFF_NOTRAILERS
IFF_RUNNING = 0x40, /* Resources allocated. */
# define IFF_RUNNING IFF_RUNNING
IFF_NOARP = 0x80, /* No address resolution protocol. */
# define IFF_NOARP IFF_NOARP
IFF_PROMISC = 0x100, /* Receive all packets. */
# define IFF_PROMISC IFF_PROMISC
/* Not supported */
IFF_ALLMULTI = 0x200, /* Receive all multicast packets. */
# define IFF_ALLMULTI IFF_ALLMULTI
IFF_MASTER = 0x400, /* Master of a load balancer. */
# define IFF_MASTER IFF_MASTER
IFF_SLAVE = 0x800, /* Slave of a load balancer. */
# define IFF_SLAVE IFF_SLAVE
IFF_MULTICAST = 0x1000, /* Supports multicast. */
# define IFF_MULTICAST IFF_MULTICAST
IFF_PORTSEL = 0x2000, /* Can set media type. */
# define IFF_PORTSEL IFF_PORTSEL
IFF_AUTOMEDIA = 0x4000, /* Auto media select active. */
# define IFF_AUTOMEDIA IFF_AUTOMEDIA
IFF_DYNAMIC = 0x8000 /* Dialup device with changing addresses. */
# define IFF_DYNAMIC IFF_DYNAMIC
};
网络设备 的 套接字(socket) 接口
http://blog.sina.com.cn/s/blog_4bb620d50100083u.html
#include <sys/ioctl.h>
#include <net/if.h>
描述 (DESCRIPTION)
本手册 描述 用于 配置 网络设备 的 套接字(socket) 接口.
Linux 支持 一些 配置 网络设备 的 标准 ioctl. 他们用于任意的套接字 描述符, 而 无须 了解 其 类型 或 系列. 他们 传递一个 ifreq 结构:
struct ifreq
{
char ifr_name[IFNAMSIZ]; /* Interface name */ union { struct sockaddr ifr_addr; struct sockaddr ifr_dstaddr; struct sockaddr ifr_broadaddr; struct sockaddr ifr_netmask; struct sockaddr ifr_hwaddr; short ifr_flags; int ifr_ifindex; int ifr_metric; int ifr_mtu; struct ifmap ifr_map; char ifr_slave[IFNAMSIZ]; char ifr_newname[IFNAMSIZ]; char * ifr_data; }; }
struct ifconf { int ifc_len; /* size of buffer */
union {
char * ifc_buf; /* buffer ddress */ struct ifreq *ifc_req; /* array of structures */
}; };
一般说来, ioctl 通过 把 ifr_name 设置为 接口 的 名字 来指定 将要 操作 的 设备. 结构的 其他成员 可以 分享 内存.
IOCTLS
如果 某个 ioctl 标记为 特权操作, 那么 操作时 需要 有效uid 为 0, 或者 拥有 CAP_NET_ADMIN 能力. 否则 将 返回 EPERM .
SIOCGIFNAME
给定 ifr_ifindex, 返回 ifr_name 中 的 接口名字. 这是唯一 返回 ifr_name 内容 的 ioctl.
- SIOCGIFINDEX
- 把 接口 的 索引 存入 ifr_ifindex.
- SIOCGIFFLAGS, SIOCSIFFLAGS
- 读取 或 设置 设备的 活动标志字. ifr_flags 包含下列值的屏蔽位:
设备标志 IFF_UP 接口正在运行. IFF_BROADCAST 有效的广播地址集. IFF_DEBUG 内部调试标志. IFF_LOOPBACK 这是自环接口. IFF_POINTOPOINT 这是点到点的链路接口. IFF_RUNNING 资源已分配. IFF_NOARP 无arp协议, 没有设置第二层目的地址. IFF_PROMISC 接口为杂凑(promiscuous)模式. IFF_NOTRAILERS 避免使用trailer . IFF_ALLMULTI 接收所有组播(multicast)报文. IFF_MASTER 主负载平衡群(bundle). IFF_SLAVE 从负载平衡群(bundle). IFF_MULTICAST 支持组播(multicast). IFF_PORTSEL 可以通过ifmap选择介质(media)类型. IFF_AUTOMEDIA 自动选择介质. IFF_DYNAMIC 接口关闭时丢弃地址. 设置 活动标志字 是 特权操作, 但是 任何进程 都可以读取标志字.
- SIOCGIFMETRIC, SIOCSIFMETRIC
- 使用 ifr_metric 读取 或 设置 设备的 metric 值. 该功能目前 还没有 实现. 读取操作 使 ifr_metric 置 0, 而设置操作则 返回 EOPNOTSUPP.
- SIOCGIFMTU, SIOCSIFMTU
- 使用 ifr_mtu 读取 或 设置 设备的 MTU(最大传输单元). 设置 MTU 是 特权操作. 过小的 MTU 可能 导致 内核 崩溃.
- SIOCGIFHWADDR, SIOCSIFHWADDR
- 使用 ifr_hwaddr 读取 或 设置 设备的 硬件地址. 设置硬件地址 是 特权操作.
- SIOCSIFHWBROADCAST
- 使用 ifr_hwaddr 读取 或 设置 设备的 硬件广播地址. 这是个特权操作.
- SIOCGIFMAP, SIOCSIFMAP
- 使用 ifr_map 读取 或 设置 接口的 硬件参数.
设置这个参数是 特权操作.
struct ifmap
{
unsigned long mem_start;
unsigned long mem_end;
unsigned short base_addr;
unsigned char irq;
unsigned char dma;
unsigned char port;
};
-
对 ifmap 结构 的 解释 取决于 设备驱动程序 和 体系结构.
- SIOCADDMULTI, SIOCDELMULTI
- 使用 ifr_hwaddr 在 设备的 链路层 组播过滤器 (multicase filter) 中 添加 或 删除 地址. 这些是 特权操作. 参看 packet(7).
- SIOCGIFTXQLEN, SIOCSIFTXQLEN
- 使用 ifr_qlen 读取 或 设置 设备的 传输队列长度. 设置传输队列长度 是 特权操作.
- SIOCSIFNAME
- 把 ifr_ifindex 中 指定的 接口名字 改成 ifr_newname. 这是个 特权操作.
- SIOCGIFCONF
- 返回 接口地址(传输层) 列表. 出于 兼容性, 目前 只代表 AF_INET 地址. 用户 传送 一个 ifconf 结构 作为 ioctl 的 参数. 其中 ifc_req 包含 一个 指针 指向 ifreq 结构数组, 他的长度以字节 为单位 存放在 ifc_len 中. 内核 用 所有 当前的 L3(第三层?) 接口地址 填充 ifreqs, 这些 接口 正在 运行: ifr_name 存放 接口名字 (eth0:1等), ifr_addr 存放地址. 内核 在 ifc_len 中 返回 实际长度; 如果 他 等于初始长度, 表示溢出了, 用户 应该 换一个 大些的 缓冲区 重试 一下. 没有 发生错误时 ioctl 返回 0, 否则 返回 -1, 溢出 不算 错误.
大多数 协议 使用 自己的 ioctl 配置 协议 特定的 接口 操作. 具体情况参看 协议的 帮助手册. 要配置 IP 地址 可以 参看 ip(7).
另外, 某些 设备 有 专用的 ioctl, 这里 不做 叙述.
注意 (NOTE)
严格说来 SIOCGIFCONF 是 专门 针对 IP 的, 它 属于 ip(7).
注意 (NOTE)
可以 通过 /proc/net/dev 看到 没有 地址 或 没有 IFF_RUNNING 标志 的 接口名字.
/* Interface request structure used for socket ioctl's. All interface
ioctl's must have parameter definitions which begin with ifr_name.
The remainder may be interface specific. */
struct ifreq
{
# define IFHWADDRLEN 6
# define IFNAMSIZ IF_NAMESIZE
union
{
char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
} ifr_ifrn;
union
{
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
short int ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
__caddr_t ifru_data;
} ifet_ifru;
};
# define ifr_name ifr_ifrn.ifrn_name /* interface name */
# define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
# define ifr_addr ifr_ifru.ifru_addr /* address */
# define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
# define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
# define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
# define ifr_flags ifr_ifru.ifru_flags /* flags */
# define ifr_metric ifr_ifru.ifru_ivalue /* metric */
# define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
# define ifr_map ifr_ifru.ifru_map /* device map */
# define ifr_slave ifr_ifru.ifru_slave /* slave device */
# define ifr_data ifr_ifru.ifru_data /* for use by interface */
# define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
# define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
# define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */
# define ifr_newname ifr_ifru.ifru_newname /* New name */
# define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)
# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)
# define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)