paper 78:sniff抓包程序片斷

#define INTERFACE "eth0"
#define MAX_SIZE 65535

int init_raw_socket();
int open_promisc(char *interface, int sockfd);

int main()
{
    int sockfd;
    int bytes_recv;
    int addr_len;

    char recv_buff[MAX_SIZE];
    struct sockaddr_in from_addr;
    struct ip *ip;
    struct tcp *tcp;

    sockfd = init_raw_socket();
    open_promisc(INTERFACE, sockfd);

    addr_len = sizeof(from_addr);

    while (1)
    {
        bytes_recv = recvfrom(sockfd, recv_buff, MAX_SIZE - 1, 0,
            (struct sockaddr_in*)&from_addr, &addr_len));
        if (bytes_recv < 0)
        {
            perror("recvfrom error");
            exit(EXIT_FAILURE);
        }

        printf("receive %d bytes from %s\n", bytes_recv, 
            inet_ntoa(from_addr.sin_addr));

        ip = (struct ip*)recv_buff;
        if (ip->ip_protocol == 6)
        {
            printf("IP header length ::: %d\n",ip->ip_length);  
            printf("Protocol ::: %d\n",ip->ip_protocol);  
            tcp = (struct tcp *)(buffer + (4*ip->ip_length));  
            printf("Source port ::: %d\n",ntohs(tcp->tcp_source_port));  
            printf("Dest port ::: %d\n",ntohs(tcp->tcp_dest_port));  
        }
    }
    return 0;
}

int init_raw_socket()
{
    int sockfd;
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sockfd < 0)
    {
        perror("create socker error");
        exit(EXIT_FAILURE);
    }
    
    return sockfd;
}

int open_promisc(char *interface, int sockfd)
{
    struct ifreq ifr;
    strncpy(ifr.ifr_name, interface, strlen(interface) + 1);
    if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) == -1)
    {
        perror("couldn't rettrive flags for the interface");
        exit(EXIT_FAILURE);
    }

    ifr.ifr_flags |= IFF_PROMISC;
    if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) == -1)
    {
        perror("couldn't set the promisc flags");
        exit(EXIT_FAILURE);
    }

    printf("set interface: %s to promisc\n", interface);
    return 0;



關於open_promisc打開網口混合模式
#include <sys/ioctl.h> 
#include <net/if.h>數組

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 address */
struct ifreq *ifc_req; /* array of structures */
};
};

通常說來, ioctl 經過 把 ifr_name 設置爲 接口 的 名字 來 指定 將要 操做 的 設備. 結構的 其餘成員 能夠 分享 內存.socket

若是 某個 ioctl 標記爲 特權操做, 那麼 操做時 須要 有效uid 爲 0, 或者 擁有 CAP_NET_ADMIN 能力. 不然 將 返回 EPERM .tcp

 

SIOCGIFNAME
給定  ifr_ifindex, 返回  ifr_name 中 的 接口名字. 這是 惟一 返回  ifr_name 內容 的 ioctl.
SIOCGIFINDEX
把 接口 的 索引 存入  ifr_ifindex.
SIOCGIFFLAGSSIOCSIFFLAGS
讀取 或 設置 設備的 活動標誌字.  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 接口關閉時丟棄地址.

設置 活動標誌字 是 特權操做, 可是 任何進程 均可以 讀取 標誌字.ui

SIOCGIFMETRICSIOCSIFMETRIC
使用  ifr_metric 讀取 或 設置 設備的 metric 值. 該功能 目前 尚未 實現. 讀取操做 使  ifr_metric 置 0, 而 設置操做 則 返回  EOPNOTSUPP.
SIOCGIFMTUSIOCSIFMTU
使用  ifr_mtu 讀取 或 設置 設備的 MTU(最大傳輸單元). 設置 MTU 是 特權操做. 太小的 MTU 可能 致使 內核 崩潰.
SIOCGIFHWADDRSIOCSIFHWADDR
使用  ifr_hwaddr 讀取 或 設置 設備的 硬件地址. 設置 硬件地址 是 特權操做.
SIOCSIFHWBROADCAST
使用  ifr_hwaddr 讀取 或 設置 設備的 硬件廣播地址. 這是個 特權操做.
SIOCGIFMAPSIOCSIFMAP
使用  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 結構 的 解釋 取決於 設備驅動程序 和 體系結構.spa

SIOCADDMULTISIOCDELMULTI
使用  ifr_hwaddr 在 設備的 鏈路層 組播過濾器 (multicase filter) 中 添加 或 刪除 地址. 這些是 特權操做. 
SIOCGIFTXQLENSIOCSIFTXQLEN
使用  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, 溢出 不算 錯誤.


相關結構體:
/*structure of an ip header*/    
struct ip {      
unsigned int ip_length:4; /*little-endian*/    
unsigned int ip_version:4;   
unsigned char ip_tos;    
unsigned short ip_total_length;     
unsigned short ip_id;     
unsigned short ip_flags;   
unsigned char ip_ttl;   
unsigned char ip_protocol;   
unsigned short ip_cksum;   
unsigned int ip_source; unsigned int ip_dest;     
};   
     
/* Structure of a TCP header */   
struct tcp {   
unsigned short tcp_source_port;   
unsigned short tcp_dest_port;   
unsigned int tcp_seqno;     
unsigned int tcp_ackno;   
unsigned int tcp_res1:4, /*little-endian*/   
tcp_hlen:4,   
tcp_fin:1,   
tcp_syn:1,   
tcp_rst:1,   
tcp_psh:1,   
tcp_ack:1,   
tcp_urg:1,   
tcp_res2:2;   
unsigned short tcp_winsize;   
unsigned short tcp_cksum;   
unsigned short tcp_urgent;   
};   
/*********************EOF***********************************/  
指針

相關文章
相關標籤/搜索