【问题标题】:forwarding packets by changing header contents(Ether, network layer) and using pcap_inject in ubuntu(C program)通过更改标头内容(以太网,网络层)和在 ubuntu(C 程序)中使用 pcap_inject 来转发数据包
【发布时间】:2011-12-17 05:45:01
【问题描述】:

我想制作一个 C 程序,其中一台笔记本电脑(比如服务器)充当另一台笔记本电脑(比如客户端)的 HTTP 转发器(它可以通过 WLAN 访问互联网),并且两台笔记本电脑通过以下方式相互连接局域网。

我实施的步骤是:

1) (在子进程中)监听 eth1 并且如果目标端口 == 80 ,则修改数据包 - (a) 在 router.txt 中写入目的 ip 和源端口 (b) 更改源 IP、源和目标 MAC 地址、校验和 (c) 使用 pcap_inject 在 wlan1 接口中注入修改后的数据包。

2)(在父进程中)监听wlan1,如果router.txt中存在源ip&目的端口号&源端口==80,则修改数据包- (a) 更改目标 ip、源和目标 mac 地址、校验和。 (b) 使用 pcap_inject 将修改后的数据包注入 eth0 接口。

分析流量时出现问题 - 数据包由 wlan1 接口成功发送,但我没有收到来自目标 IP 的任何响应(比如 74.125.236.52(google.com))

主要原因可能是我没有正确构建数据包(但我已经彻底检查了每个细节(尤其是校验和)),或者我需要更改标头中的更多细节。我不知道为什么我没有从服务器得到响应。

PS - 1) 如果我犯了一些非常基本的错误,请告诉我(比如我的方法是错误的,或者这种方法永远无法用于转发数据包)。

2) 我总能获得客户端笔记本电脑的互联网连接。制作这个程序的全部目的是了解转发的工作原理。

#include <stdio.h>
#include <pcap.h>
#include <pcap/pcap.h>
#include <stdlib.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <netdb.h>
#include <ifaddrs.h>
typedef struct router_table_struct 
{   uint8_t port;   
    char ip[16];
}router_table_struct;

int counter=0;  
#define ETHERNET_HEADER_LEN 14
#define WIRELESS_INTERFACE "wlan1" //////////
#define ETHERNET_INTERFACE "eth0"
#define ETHER_ADDRESS_PATH_WIRELESS "/sys/class/net/wlan1/address" /////
#define ETHER_ADDRESS_PATH_LAN "/sys/class/net/eth0/address"
#define ROUTER_TABLE_PATH "/home/---/router_table.txt"
#define ETHER_ADDRESS_ROUTER "**"
#define ETHER_ADDRESS_PRAGYA_LAN "**"
#define IP_PRAGYA_LAN "****"

u_char* modify_packet(u_char *pkt_ptr, pcap_t *eth_handle, pcap_t *wlan_handle, int pkt_type, int len);
int change_ether_addr_dest(uint8_t pkt_type, struct ether_header *eth_hdr);
int change_ether_addr_source(uint8_t pkt_type, struct ether_header *eth_hdr);
int change_ip_addr(struct ip *ip_hdr, uint8_t pkt_type);
uint16_t ip_checksum(struct ip *ip_hdr);
int* parse_ip_address(char *);
uint8_t *parse_ether_address(char *ether_addr_str);
int check_if_packet_exists(char *ipaddr,  uint16_t port);
int add_entry_in_router_table(char *ipaddr, uint16_t port);

int show_packet_contents(u_char *pkt_ptr, int len);

int main() 
{ 
    struct pcap_pkthdr header;
    u_char *pkt_ptr;
    pcap_t *wlan_handle, *eth_handle;  
    char errbuf[PCAP_ERRBUF_SIZE]; 
    char *source_ip, *dest_ip; 
    uint8_t dest_port, source_port;
    eth_handle = pcap_open_live(ETHERNET_INTERFACE,65535,0, 0, errbuf);//////
    wlan_handle = pcap_open_live(WIRELESS_INTERFACE,65535,0, 0,errbuf); /////
    if (eth_handle == NULL)
    {   printf("Couldn't open ethernet handle: %s\n",errbuf); return(2); } 
    if (wlan_handle == NULL)
        {   printf("Couldn't open wlan_handle: %s\n",errbuf); return(2); } 
    int c;

    pid_t pid = fork();

    if(pid == 0) /*** for reading packets from local LAN, forwarding them to wireless router and saving them ********/
    {   c = 0;  
        while(c < 50)
        {       pkt_ptr = (u_char *)pcap_next(eth_handle,&header); ////////
            struct ether_header *eth_hdr = (struct ether_header *)pkt_ptr;
                struct ip *ip_hdr = (struct ip *)(pkt_ptr + 14); 
                struct tcphdr *tcp_hdr = (struct tcphdr *)(pkt_ptr + 14 + 20);

            printf("local LAN count: %d: %s.%hu %d",c, inet_ntoa(ip_hdr->ip_src), ntohs(tcp_hdr->source),ntohs(ip_hdr->ip_len));
            printf(" : %s.%hu  version: %d\n", inet_ntoa(ip_hdr->ip_dst), ntohs(tcp_hdr->dest), ip_hdr->ip_v);

            dest_port = ntohs(tcp_hdr->dest);       
            source_ip = inet_ntoa(ip_hdr->ip_src);
            if(!strcmp(source_ip, IP_PRAGYA_LAN) && dest_port == 80) ///////
            {   
                u_char *ptr = modify_packet(pkt_ptr, eth_handle, wlan_handle, (uint8_t)1, header.len);

                int packets_injected = pcap_inject(wlan_handle,(const u_char *)ptr, header.len); ///////////
                printf("\ninjected: %d\n",packets_injected); 
                if(packets_injected == -1) { printf("error: %s\n",pcap_geterr(wlan_handle)); }                  
            }
            c++;
        }  
    }
    else    /****** for reading packets from wireless router, checking if they need to be forwarded and forwarding them to local LAN*******/
    {   c = 0;  
        while(c < 150)
        {   pkt_ptr = (u_char *)pcap_next(wlan_handle,&header); ///////
            struct ether_header *eth_hdr = (struct ether_header *)pkt_ptr;

                struct ip *ip_hdr = (struct ip *)(pkt_ptr + 14); 
                struct tcphdr *tcp_hdr = (struct tcphdr *)(pkt_ptr + 14 + 20);

            printf("Wireless count: %d: %s.%u %d",c, inet_ntoa(ip_hdr->ip_src), ntohs(tcp_hdr->source),ntohs(ip_hdr->ip_len));
            printf(" : %s.%u  version: %d\n", inet_ntoa(ip_hdr->ip_dst), ntohs(tcp_hdr->dest), ip_hdr->ip_v);

            char *ip_source=inet_ntoa(ip_hdr->ip_src);
            dest_port = ntohs(tcp_hdr->dest);
            if(check_if_packet_exists(ip_source, dest_port) && ntohs(tcp_hdr->source) == 80 && ntohs(eth_hdr->ether_type) == 0x0800)
            {   
                u_char *ptr = modify_packet(pkt_ptr, eth_handle, wlan_handle, (uint8_t)0, header.len);

                int packets_injected = pcap_inject(eth_handle,(const void *)ptr, header.len); ////
                printf("\ninjected: %d\n",packets_injected); 
                if(packets_injected == -1){  printf("error: %s\n",pcap_geterr(eth_handle)); }   
            }
            c++;
        }  
        waitpid(pid, NULL, 0);
        pcap_close(eth_handle);  
        pcap_close(wlan_handle);
    }
} 

uint16_t ip_checksum (struct ip *ip_hdr)
{   int *ipsrc_parse = parse_ip_address(inet_ntoa(ip_hdr->ip_src));
    int *ipdst_parse = parse_ip_address(inet_ntoa(ip_hdr->ip_dst)); 

     int sum = (((unsigned int)ip_hdr->ip_v<<12 | (unsigned int)ip_hdr->ip_hl<<8 | (ip_hdr->ip_tos)) +
            (ntohs(ip_hdr->ip_len))+
            (ntohs(ip_hdr->ip_id))+
            (ntohs(ip_hdr->ip_off))+
            ((ip_hdr->ip_ttl)<<8 | (ip_hdr->ip_p))+
            (ipsrc_parse[0]<<8 | ipsrc_parse[1])+
            (ipsrc_parse[2]<<8 | ipsrc_parse[3])+
            (ipdst_parse[0]<<8 | ipdst_parse[1])+
            (ipdst_parse[2]<<8 | ipdst_parse[3]));

    int chk_sum = ((sum & 0x0000ffff) + ((sum & 0xffff0000)>>16));

    return (uint16_t)(~chk_sum);
}

u_char *modify_packet(u_char *pkt_ptr, pcap_t *eth_handle, pcap_t *wlan_handle, int pkt_type, int len)
{   //printf("inside modify packet\n");

    printf("contents of the pakcet without modification: \n");
    show_packet_contents(pkt_ptr, len);

    struct ether_header *eth_hdr = (struct ether_header *)pkt_ptr;
        struct ip *ip_hdr = (struct ip *)(pkt_ptr + ETHERNET_HEADER_LEN); //point to an IP header structure

    int header_len = (int)(ip_hdr->ip_hl*4);
        struct tcphdr *tcp_hdr = (struct tcphdr *)(pkt_ptr + ETHERNET_HEADER_LEN + header_len);

    if(pkt_type == 0)
    {   inet_aton(IP_PRAGYA_LAN, &ip_hdr->ip_dst);
    }

    else
    {   if(!check_if_packet_exists(inet_ntoa(ip_hdr->ip_dst),(uint16_t)( ntohs(tcp_hdr->source)) ))
            add_entry_in_router_table(inet_ntoa(ip_hdr->ip_dst),(uint16_t)ntohs(tcp_hdr->source) );

        change_ip_addr(ip_hdr, pkt_type);
    }
    change_ether_addr_source(pkt_type, eth_hdr);
    change_ether_addr_dest(pkt_type, eth_hdr);

    ip_hdr->ip_sum = (htons)(ip_checksum(ip_hdr));

    printf("end of modify packet\n");

    return pkt_ptr;
}

int* parse_ip_address(char *ipaddr)
{   //printf("parse ip address\n");
    int i=-1, num = 0, p = 1,j=0;
    int *ipaddr_parse = malloc(sizeof(int)*4);
    char ch;
    do
    {   i++;
        ch = ipaddr[i];
        if(ch == '.' || ch == '\0')
        {   ipaddr_parse[j] = num;
            p = 1;
            num = 0;
            j++;    
        }
        else
        {   num = num*p + (ch-48);              
            if (p == 1) p = 10;
        }   
    } while(ipaddr[i]!='\0');
    //printf("\n%d %d %d %d\n",ipaddr_parse[0], ipaddr_parse[1], ipaddr_parse[2], ipaddr_parse[3]);
    return ipaddr_parse;
}

uint8_t *parse_ether_address(char *ether_addr_str)
{   //printf("parse ether address\n");
    int i =-1,c,j=0; 
    char ch;
    uint8_t num=0, *ether_addr = malloc(sizeof(int)*6);
    do
    {   i++;    
        ch = ether_addr_str[i];
        if(ch == ':' || ch == '\0')
        {   ether_addr[j] = num;
            num = 0;
            j++;
        }
        else
        {   c = (ch>57)? ch-87 : ch-48;
            num = num*16 + c;
        }
    } while(ether_addr_str[i] != '\0');

    printf("MAC- ");
    for(i=0;i<6;i++)
        printf("%x:",ether_addr[i]);
    printf("\n");

    return ether_addr;
}

int add_entry_in_router_table(char *ipaddr, uint16_t port)
{   //printf("add entry in router table\n");
    FILE *rtable_fp = fopen(ROUTER_TABLE_PATH,"a+");
    router_table_struct rtable_ptr;

    while((fscanf(rtable_fp, "%s %hhu", rtable_ptr.ip, &rtable_ptr.port )) !=EOF);

    fprintf(rtable_fp,"%s %hu\n", ipaddr, port);
    fclose(rtable_fp);
}

int check_if_packet_exists(char *ipaddr,  uint16_t port)
{   //printf("check if packet exists\n");
    FILE *rtable_fp = fopen(ROUTER_TABLE_PATH,"a+");
    router_table_struct rtable_ptr;

    while((fscanf(rtable_fp, "%s %hhu", rtable_ptr.ip, &rtable_ptr.port )) !=EOF) //to check if ip address is already mapped 
        {   
        if(!strcmp(ipaddr,rtable_ptr.ip) && port == rtable_ptr.port)
        {   fclose(rtable_fp);
            return 1;
        }
    }
    fclose(rtable_fp);
    return 0;

}

int change_ip_addr(struct ip *ip_hdr, uint8_t pkt_type)
{   //printf("inside change ip address\n"); 
    struct ifaddrs *ifap;
    getifaddrs(&ifap);
    char host[NI_MAXHOST], *errbuf;
    char *iface = WIRELESS_INTERFACE;
    while(ifap != NULL)
    {   if(ifap->ifa_addr->sa_family == AF_INET && !strcmp(iface,ifap->ifa_name) )  
        {   getnameinfo(ifap->ifa_addr,sizeof(struct sockaddr_in), host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
            printf("address: %s %s\n", host,ifap->ifa_name);
            break;
        }
        ifap = ifap->ifa_next;
    }gin processing the packets in this particular file, one at a time 

    inet_aton(host, &ip_hdr->ip_src);
}

int change_ether_addr_source(uint8_t pkt_type, struct ether_header *eth_hdr)
{   //printf("change_ether_addr_source\n"); 
    FILE *fp_ether;
    if(pkt_type == 0)
        fp_ether = fopen(ETHER_ADDRESS_PATH_LAN, "r");
    else
        fp_ether = fopen(ETHER_ADDRESS_PATH_WIRELESS, "r");
    char *ether_src = malloc(17);
    fscanf(fp_ether, "%s", ether_src);
    printf("%s\n",ether_src);
    fclose(fp_ether);

    uint8_t *ether_source = parse_ether_address(ether_src);
    int i;
    for(i=0;i<6;i++)
        eth_hdr->ether_shost[i] = ether_source[i];
}

int change_ether_addr_dest(uint8_t pkt_type, struct ether_header *eth_hdr)
{   //printf("inside change ether address dest\n"); 
    uint8_t *ether_dest;    
    if(pkt_type == 0)
        ether_dest = parse_ether_address(ETHER_ADDRESS_PRAGYA_LAN); 
    else
        ether_dest = parse_ether_address(ETHER_ADDRESS_ROUTER); 
    int i;
    for(i=0;i<6;i++)
        eth_hdr->ether_dhost[i] = ether_dest[i];
}


int show_packet_contents(u_char *pkt_ptr, int len)
{   
    struct ether_header *eth_hdr = (struct ether_header *)pkt_ptr;
        struct ip *ip_hdr = (struct ip *)(pkt_ptr + ETHERNET_HEADER_LEN); //point to an IP header structure

    int header_len = (int)(ip_hdr->ip_hl*4);
        struct tcphdr *tcp_hdr = (struct tcphdr *)(pkt_ptr + ETHERNET_HEADER_LEN + header_len);

    int j=0;

    printf("Packet length: %d \n",len);

    printf("ethernet source: ");
    int i;
    for(i=0;i<6;i++)
        printf("%x:",eth_hdr->ether_shost[i]);
    printf("\n");
    printf("ethernet dest: ");
    for(i=0;i<6;i++)
        printf("%x:",eth_hdr->ether_dhost[i]);
    printf("\nethernet type: %x\n",ntohs(eth_hdr->ether_type));
    printf("\n");

    printf("IP PACKET CONTENTS\n"); 

    printf("IP version      : %x\n",(unsigned int)ip_hdr->ip_v);
    printf("IP Header length: %x\n",(unsigned int)ip_hdr->ip_hl);
    printf("IP tos          : %x\n",(uint8_t)(ip_hdr->ip_tos));
    printf("IP Packet length: %x\n",(uint16_t)ntohs(ip_hdr->ip_len));
    printf("IP Id           : %x\n",(uint16_t)ntohs(ip_hdr->ip_id));
    printf("IP offset       : %x\n",(uint16_t)ntohs(ip_hdr->ip_off));
    printf("IP TTL          : %x\n",(uint8_t)(ip_hdr->ip_ttl));
    printf("IP protocol     : %x\n",(uint8_t)(ip_hdr->ip_p));
    printf("IP checksum     : %x\n",(uint16_t)ntohs(ip_hdr->ip_sum));
    printf("IP src_addr     : %s\n",inet_ntoa(ip_hdr->ip_src));
    printf("IP dst_addr     : %s\n",inet_ntoa(ip_hdr->ip_dst));

    printf("TCP_PACKET_CONTENTS\n");
    printf("source port: %hu\n",(uint16_t)ntohs(tcp_hdr->source));
    printf("destination port: %hu\n",(uint16_t)ntohs(tcp_hdr->dest));
}

似乎我现在正在从服务器收到回复(wireshark 显示),但页面仍然没有加载......有时错误是:“与 74.125.236.52 的连接被中断”或有时“。 ....72.218.3.115 响应时间过长.."

来自服务器的响应包括 tcp 握手包(syn、syn-ack、ack)和一个“http get”请求。

这是发送的一个这样的数据包的wireshark转储。 (162.254.3.1 是客户端笔记本电脑的 IP 地址和 125.252.226.160(一些随机站点)

3 0.000370 162.254.3.1 125.252.226.160 TCP 51442 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460

5 0.063316 125.252.226.160 162.254.3.1 TCP http > 51442 [SYN, ACK] Seq=0 Ack=1 Win=5840 Len=0 MSS=1460

6 0.063568 162.254.3.1 125.252.226.160 TCP 51442 > http [ACK] Seq=1 Ack=1 Win=5840 Len=0

7 0.063996 162.254.3.1 125.252.226.160 HTTP GET / HTTP/1.1

8 0.064114 125.252.226.160 162.254.3.1 TCP http > 51443 [SYN, ACK] Seq=0 Ack=1 Win=5840 Len=0 MSS=1460

9 0.064381 162.254.3.1 125.252.226.160 TCP 51443 > http [ACK] Seq=1 Ack=1 Win=5840 Len=0

谁能建议我应该如何避免这些错误(连接超时)并看到页面加载???

【问题讨论】:

    标签: forwarding ubuntu-11.04 pcap


    【解决方案1】:

    如果你不想做一些 c/networking 实践:为什么不使用 ebtables,它与 iptables 非常相似,但在第 2 层?那个软件的目的是什么?

    【讨论】:

    • 这个项目的目的是学习转发是如何工作的(包括改变IP地址和计算校验和等)。我不知道你为什么告诉我参考 ebtables,因为问题在于我无法制作完整的数据包(因为我没有从服务器(比如谷歌)得到回复,所以我假设这个是问题。)也许,我应该提出这样的问题,例如如何使用 pcap 创建和发送网络数据包并将回复转发给客户端......就像路由器所做的那样。
    • 所以,我误会了。抱歉打扰了。
    猜你喜欢
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 2014-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-18
    • 2020-08-17
    相关资源
    最近更新 更多