六、系统网络状态相关的数据结构
6.1 ifconf
- \linux-2.6.32.63\include\linux\if.h
/* Structure used in SIOCGIFCONF request. Used to retrieve interface
configuration for machine (useful for programs which must know all
networks accessible).
*/
struct ifconf
{
int ifc_len; // Size of buffer.
union
{
__caddr_t ifcu_buf;
struct ifreq *ifcu_req; //保存每块网卡的具体信息的结构体数组
} ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf /* Buffer address. */
#define ifc_req ifc_ifcu.ifcu_req /* Array of structures. */
#define _IOT_ifconf _IOT(_IOTS(struct ifconf),1,0,0,0,0) /* not right */
6.2 ifreq
- \linux-2.6.32.63\include\linux\if.h
/*
* 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
union
{
char ifrn_name[IFNAMSIZ]; /* if 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 ifru_flags;
int ifru_ivalue;
int ifru_mtu;
struct ifmap ifru_map;
char ifru_slave[IFNAMSIZ]; /* Just fits the size */
char ifru_newname[IFNAMSIZ];
void __user * ifru_data;
struct if_settings ifru_settings;
} ifr_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 ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
-
编程示例:
#include <arpa/inet.h> #include <net/if.h> #include <net/if_arp.h> #include <netinet/in.h> #include <stdio.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <unistd.h> #define MAXINTERFACES 16 /* 最大接口数 */ int fd; /* 套接字 */ int if_len; /* 接口数量 */ struct ifreq buf[MAXINTERFACES]; /* ifreq结构数组 */ struct ifconf ifc; /* ifconf结构 */ int main(argc, argv) { /* 建立IPv4的UDP套接字fd */ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket(AF_INET, SOCK_DGRAM, 0)"); return -1; } /* 初始化ifconf结构 */ ifc.ifc_len = sizeof(buf); ifc.ifc_buf = (caddr_t) buf; /* 获得接口列表 */ if (ioctl(fd, SIOCGIFCONF, (char *) &ifc) == -1) { perror("SIOCGIFCONF ioctl"); return -1; } if_len = ifc.ifc_len / sizeof(struct ifreq); /* 接口数量 */ printf("接口数量:%d\n", if_len); while (if_len > 0) /* 遍历每个接口 */ { printf("接口:%s/n", buf[if_len].ifr_name); /* 接口名称 */ /* 获得接口标志 */ if (!(ioctl(fd, SIOCGIFFLAGS, (char *) &buf[if_len]))) { /* 接口状态 */ if (buf[if_len].ifr_flags & IFF_UP) { printf("接口状态: UP\n"); } else { printf("接口状态: DOWN\n"); } } else { char str[256]; sprintf(str, "SIOCGIFFLAGS ioctl %s", buf[if_len].ifr_name); perror(str); } /* IP地址 */ if (!(ioctl(fd, SIOCGIFADDR, (char *) &buf[if_len]))) { printf("IP地址:%s/n",\ (char*)inet_ntoa(((struct sockaddr_in*)(&buf[if_len].ifr_addr))->sin_addr)); } else { char str[256]; sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name); perror(str); } /* 子网掩码 */ if (!(ioctl(fd, SIOCGIFNETMASK, (char *) &buf[if_len]))) { printf("子网掩码:%s/n", (char*)inet_ntoa(((struct sockaddr_in*)(&buf[if_len].ifr_addr))->sin_addr)); } else { char str[256]; sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name); perror(str); } /* 广播地址 */ if (!(ioctl(fd, SIOCGIFBRDADDR, (char *) &buf[if_len]))) { printf("广播地址:%s/n", (char*)inet_ntoa(((struct sockaddr_in*) (&buf[if_len].ifr_addr))->sin_addr)); } else { char str[256]; sprintf(str, "SIOCGIFADDR ioctl %s", buf[if_len].ifr_name); perror(str); } /*MAC地址 */ if (!(ioctl(fd, SIOCGIFHWADDR, (char *) &buf[if_len]))) { printf("MAC地址:%02x:%02x:%02x:%02x:%02x:%02x/n/n", (unsigned char) buf[if_len].ifr_hwaddr.sa_data[0], (unsigned char) buf[if_len].ifr_hwaddr.sa_data[1], (unsigned char) buf[if_len].ifr_hwaddr.sa_data[2], (unsigned char) buf[if_len].ifr_hwaddr.sa_data[3], (unsigned char) buf[if_len].ifr_hwaddr.sa_data[4], (unsigned char) buf[if_len].ifr_hwaddr.sa_data[5]); } else { char str[256]; sprintf(str, "SIOCGIFHWADDR ioctl %s", buf[if_len].ifr_name); perror(str); } }//while end //关闭socket close(fd); return 0; }
-
拓展链接
- http://blog.csdn.net/jk110333/article/details/8832077
- http://www.360doc.com/content/12/0314/15/5782959_194281431.shtml
6.3 socket
- \linux-2.6.32.63\include\linux\net.h
struct socket
{
/*
1. state:socket状态
typedef enum
{
SS_FREE = 0, //该socket还未分配
SS_UNCONNECTED, //未连向任何socket
SS_CONNECTING, //正在连接过程中
SS_CONNECTED, //已连向一个socket
SS_DISCONNECTING //正在断开连接的过程中
}socket_state;
*/
socket_state state;
kmemcheck_bitfield_begin(type);
/*
2. type:socket类型
enum sock_type
{
SOCK_STREAM = 1, //stream (connection) socket
SOCK_DGRAM = 2, //datagram (conn.less) socket
SOCK_RAW = 3, //raw socket
SOCK_RDM = 4, //reliably-delivered message
SOCK_SEQPACKET = 5, //sequential packet socket
SOCK_DCCP = 6, //Datagram Congestion Control Protocol socket
SOCK_PACKET = 10, //linux specific way of getting packets at the dev level.
};
*/
short type;
kmemcheck_bitfield_end(type);
/*
3. flags:socket标志
1) #define SOCK_ASYNC_NOSPACE 0
2) #define SOCK_ASYNC_WAITDATA 1
3) #define SOCK_NOSPACE 2
4) #define SOCK_PASSCRED 3
5) #define SOCK_PASSSEC 4
*/
unsigned long flags;
//fasync_list is used when processes have chosen asynchronous handling of this 'file'
struct fasync_struct *fasync_list;
//4. Not used by sockets in AF_INET
wait_queue_head_t wait;
//5. file holds a reference to the primary file structure associated with this socket
struct file *file;
//6. sk contains most of the useful state associated with a socket.
struct sock *sk;
//7. ops:定义了当前socket的处理函数
const struct proto_ops *ops;
};
6.4 sock
- struct sock本身不能获取到当前socket的IP、Port相关信息,要通过
inet_sk()
进行转换得到struct inet_sock
才能得到IP、Port相关信息。但struct sock保存了当前socket大量的元描述信息。 - \linux-2.6.32.63\include\net\sock.h
struct sock
{
/*
* Now struct inet_timewait_sock also uses sock_common, so please just
* don't add nothing before this first member (__sk_common) --acme
*/
//shared layout with inet_timewait_sock
struct sock_common __sk_common;
#define sk_node __sk_common.skc_node
#define sk_nulls_node __sk_common.skc_nulls_node
#define sk_refcnt __sk_common.skc_refcnt
#define sk_copy_start __sk_common.skc_hash
#define sk_hash __sk_common.skc_hash
#define sk_family __sk_common.skc_family
#define sk_state __sk_common.skc_state
#define sk_reuse __sk_common.skc_reuse
#define sk_bound_dev_if __sk_common.skc_bound_dev_if
#define sk_bind_node __sk_common.skc_bind_node
#define sk_prot __sk_common.skc_prot
#define sk_net __sk_common.skc_net
kmemcheck_bitfield_begin(flags);
//mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN
unsigned int sk_shutdown : 2,
//%SO_NO_CHECK setting, wether or not checkup packets
sk_no_check : 2,
//%SO_SNDBUF and %SO_RCVBUF settings
sk_userlocks : 4,
//which protocol this socket belongs in this network family
sk_protocol : 8,
//socket type (%SOCK_STREAM, etc)
sk_type : 16;
kmemcheck_bitfield_end(flags);
int sk_rcvbuf; //size of receive buffer in bytes
socket_lock_t sk_lock; //synchronizer
/*
* The backlog queue is special, it is always used with
* the per-socket spinlock held and requires low latency
* access. Therefore we special case it's implementation.
*/
struct
{
struct sk_buff *head;
struct sk_buff *tail;
} sk_backlog;
wait_queue_head_t *sk_sleep; //sock wait queue
struct dst_entry *sk_dst_cache; //destination cache
#ifdef CONFIG_XFRM
struct xfrm_policy *sk_policy[2]; //flow policy
#endif
rwlock_t sk_dst_lock; //destination cache lock
atomic_t sk_rmem_alloc; //receive queue bytes committed
atomic_t sk_wmem_alloc; //transmit queue bytes committed
atomic_t sk_omem_alloc; //"o" is "option" or "other"
int sk_sndbuf; //size of send buffer in bytes
struct sk_buff_head sk_receive_queue; //incoming packets
struct sk_buff_head sk_write_queue; //Packet sending queue
#ifdef CONFIG_NET_DMA
struct sk_buff_head sk_async_wait_queue; //DMA copied packets
#endif
int sk_wmem_queued; //persistent queue size
int sk_forward_alloc; //space allocated forward
gfp_t sk_allocation; //allocation mode
int sk_route_caps; //route capabilities (e.g. %NETIF_F_TSO)
int sk_gso_type; //GSO type (e.g. %SKB_GSO_TCPV4)
unsigned int sk_gso_max_size; //Maximum GSO segment size to build
int sk_rcvlowat; //%SO_RCVLOWAT setting
/*
1. %SO_LINGER (l_onoff)
2. %SO_BROADCAST
3. %SO_KEEPALIVE
4. %SO_OOBINLINE settings
5. %SO_TIMESTAMPING settings
*/
unsigned long sk_flags;
unsigned long sk_lingertime; //%SO_LINGER l_linger setting
struct sk_buff_head sk_error_queue; //rarely used
//sk_prot of original sock creator (see ipv6_setsockopt, IPV6_ADDRFORM for instance)
struct proto *sk_prot_creator;
//used with the callbacks in the end of this struct
rwlock_t sk_callback_lock;
//last error
int sk_err,
//rrors that don't cause failure but are the cause of a persistent failure not just 'timed out'
sk_err_soft;
//raw/udp drops counter
atomic_t sk_drops;
//always used with the per-socket spinlock held
//current listen backlog
unsigned short sk_ack_backlog;
//listen backlog set in listen()
unsigned short sk_max_ack_backlog;
//%SO_PRIORITY setting
__u32 sk_priority;
//%SO_PEERCRED setting
struct ucred sk_peercred;
//%SO_RCVTIMEO setting
long sk_rcvtimeo;
//%SO_SNDTIMEO setting
long sk_sndtimeo;
//socket filtering instructions
struct sk_filter *sk_filter;
//private area, net family specific, when not using slab
void *sk_protinfo;
//sock cleanup timer
struct timer_list sk_timer;
//time stamp of last packet received
ktime_t sk_stamp;
//Identd and reporting IO signals
struct socket *sk_socket;
//RPC layer private data
void *sk_user_data;
//cached page for sendmsg
struct page *sk_sndmsg_page;
//front of stuff to transmit
struct sk_buff *sk_send_head;
//cached offset for sendmsg
__u32 sk_sndmsg_off;
//a write to stream socket waits to start
int sk_write_pending;
#ifdef CONFIG_SECURITY
//used by security modules
void *sk_security;
#endif
//generic packet mark
__u32 sk_mark;
/* XXX 4 bytes hole on 64 bit */
//callback to indicate change in the state of the sock
void (*sk_state_change)(struct sock *sk);
//callback to indicate there is data to be processed
void (*sk_data_ready)(struct sock *sk, int bytes);
//callback to indicate there is bf sending space available
void (*sk_write_space)(struct sock *sk);
//callback to indicate errors (e.g. %MSG_ERRQUEUE)
void (*sk_error_report)(struct sock *sk);
//callback to process the backlog
int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb);
//called at sock freeing time, i.e. when all refcnt == 0
void (*sk_destruct)(struct sock *sk);
}
6.5 proto_ops
- \linux-2.6.32.63\include\linux\net.h
struct proto_ops
{
int family;
struct module *owner;
int (*release)(struct socket *sock);
int (*bind)(struct socket *sock, struct sockaddr *myaddr, int sockaddr_len);
int (*connect)(struct socket *sock, struct sockaddr *vaddr, int sockaddr_len, int flags);
int (*socketpair)(struct socket *sock1, struct socket *sock2);
int (*accept)(struct socket *sock, struct socket *newsock, int flags);
int (*getname)(struct socket *sock, \
struct sockaddr *addr, \
int *sockaddr_len, int peer);
unsigned int (*poll)(struct file *file, \
struct socket *sock, \
struct poll_table_struct *wait);
int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);
int (*compat_ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);
int (*listen)(struct socket *sock, int len);
int (*shutdown) (struct socket *sock, int flags);
int (*setsockopt)(struct socket *sock, int level,\
int optname, char __user *optval, unsigned int optlen);
int (*getsockopt)(struct socket *sock, int level, \
int optname, char __user *optval, int __user *optlen);
int (*compat_setsockopt)(struct socket *sock, int level,\
int optname, char __user *optval, unsigned int optlen);
int (*compat_getsockopt)(struct socket *sock, int level, \
int optname, char __user *optval, int __user *optlen);
int (*sendmsg)(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len);
/* Notes for implementing recvmsg:
* ===============================
* msg->msg_namelen should get updated by the recvmsg handlers
* iff msg_name != NULL. It is by default 0 to prevent
* returning uninitialized memory to user space. The recvfrom
* handlers can assume that msg.msg_name is either NULL or has
* a minimum size of sizeof(struct sockaddr_storage).
*/
int (*recvmsg)(struct kiocb *iocb, struct socket *sock, \
struct msghdr *m, size_t total_len, int flags);
int (*mmap)(struct file *file, struct socket *sock, struct vm_area_struct * vma);
ssize_t (*sendpage)(struct socket *sock, \
struct page *page, int offset, \
size_t size, int flags);
ssize_t (*splice_read)(struct socket *sock,\
loff_t *ppos, struct pipe_inode_info *pipe, \
size_t len, unsigned int flags);
};
6.6 inet_sock
-
在实际编程中,我们需要使用inet_sk(),将"struct sock"结果强制转换为"struct inet_sock"之后,才可以从中取出我们想要的IP、Port等信息
-
\linux-2.6.32.63\include\net\inet_sock.h
static inline struct inet_sock *inet_sk(const struct sock *sk) { return (struct inet_sock *)sk; }
-
inet_sock的结构体定义如下
struct inet_sock { /* sk and pinet6 has to be the first two members of inet_sock */ struct sock sk; //ancestor class #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) struct ipv6_pinfo *pinet6; //pointer to IPv6 control block #endif /* Socket demultiplex comparisons on incoming packets. */ //Foreign IPv4 addr __be32 daddr; //Bound local IPv4 addr __be32 rcv_saddr; //Destination port __be16 dport; //Local port __u16 num; //Sending source __be32 saddr; //Unicast TTL __s16 uc_ttl; __u16 cmsg_flags; struct ip_options_rcu *inet_opt; //Source port __be16 sport; //ID counter for DF pkts __u16 id; //TOS __u8 tos; //Multicasting TTL __u8 mc_ttl; __u8 pmtudisc; __u8 recverr:1, //is this an inet_connection_sock? is_icsk:1, freebind:1, hdrincl:1, mc_loop:1, transparent:1, mc_all:1; int mc_index; //Multicast device index __be32 mc_addr; struct ip_mc_socklist *mc_list; //info to build ip hdr on each ip frag while socket is corked struct { unsigned int flags; unsigned int fragsize; struct ip_options *opt; struct dst_entry *dst; int length; /* Total length of all frames */ __be32 addr; struct flowi fl; } cork; };
6.7 sockaddr
struct sockaddr
{
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
/* Structure describing an Internet (IP) socket address. */
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
struct sockaddr_in
{
sa_family_t sin_family; /* Address family */
__be16 sin_port; /* Port number */
struct in_addr sin_addr; /* Internet address */
/* Pad to size of `struct sockaddr'. */
unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];
};
#define sin_zero __pad /* for BSD UNIX comp. -FvK */
/* Internet address. */
struct in_addr
{
__be32 s_addr;
};