我是靠谱客的博主 单身河马,最近开发中收集的这篇文章主要介绍网络协议栈,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

 对于两台建立通讯的主机,数据传输都是从本地主机的应用层的协议出发,经过从上至下的协议处理发送给另一台主机;另一台主机物理层接收到数据后,从下至上层层通过协议处理上传至应用层。

        这个过程有点像栈的FILO,故把这些层级协议的组合叫做协议栈(也称为协议族,family)。

        这里结合netmap实现一个简单的协议栈:

#include <stdio.h>
#include <sys/poll.h>
#include <arpa/inet.h>

#define NETMAP_WITH_LIBS 
#include <net/netmap_user.h>

#pragma pack(1) //使结构体按照1字节对齐;

#define ETH_ADDR_LENGTH 6//地址长度

#define PROTO_IP    0x0800
#define PROTO_ARP   0x0806
#define PROTO_UDP   17
#define PROTO_TCP   6
#define PROTO_ICMP  1

/*arp的作用:
    1、发送请求
    2、收到了回复的arp响应之后,记录到arp表里面
*/

struct ethhdr { //以太网协议头
    unsigned char h_dst[ETH_ADDR_LENGTH];//不对内部数据进行计算,用unsigned_char;目的地址
    unsigned char h_src[ETH_ADDR_LENGTH];//源地址;
    unsigned short h_proto;
    
};//14

struct iphdr{
    unsigned char hdrlen:4,//注意这俩的顺序,version是高位(协议头是前面的是高位)
                  version:4;//方便将不同功能的位进行分配
    
    unsigned char tos;

    unsigned short totlen;//2byte

    unsigned short id;//最多65535

    unsigned short flag_offset;

    unsigned char ttl;//time to live,没经过一个网关-1,为0丢弃,回复TTL不可达

    unsigned char type;//协议的类型

    unsigned short check;

    unsigned int sip;//源ip 
    unsigned int dip;//目的ip
};//20

struct udphdr{
    unsigned short sport;
    unsigned short dport;

    unsigned short length;
    unsigned short check;//校验码
};//8

struct udppkt{
    struct ethhdr eh;//14
    struct iphdr  ip;//20
    struct udphdr udp;//8

    unsigned char data[0];//1、提前分配好的,不会越界 2、不需要确定,因为本身是变化的-------这是柔性数组或者称0长数组
};//一字节对齐:42

struct  arphdr{
    unsigned short h_type;
    unsigned short h_proto;

    unsigned char h_addrlen;
    unsigned char h_protolen;

    unsigned short oper;

    unsigned char smac[ETH_ADDR_LENGTH];//源mac地址
    unsigned int sip;

    unsigned char dmac[ETH_ADDR_LENGTH];
    unsigned int dip;
};

struct arppkt{
    struct ethhdr eh;
    struct arphdr arp;
};

struct icmphdr{
    unsigned char type;
    unsigned char code;
    
    unsigned short check;

    unsigned int other;
};

struct icmppkt{
    struct ethhdr eh;
    struct iphdr ip;    
    struct icmphdr icmp;

    unsigned char data[0];
};

struct tcphdr{

    unsigned short sport;
    unsigned short dport;

    unsigned int seqnum;//开始是个随机值,可以从0开始,也可以从5开始,保证递增就行;越界之后从0开始//这个值是指的字节的数量
    unsigned int acknum;

    unsigned char hdrlen_resv;//高4位为TCP头部长度

    unsigned char flag;

    unsigned short window;//初始化为1460(以太网头+ip头对齐之后是40字节???)

    unsigned short checksum;
    unsigned short urgent_pointer;

    unsigned int options[0];
};

struct tcppkt{
    struct ethhdr eh;
    struct iphdr ip;    
    struct tcphdr tcp;

    unsigned char data[0];
};

typedef enum _tcp_status{
    TCP_STATUS_CLOSED,
    TCP_STATUS_LISTEN,
    TCP_STATUS_SYN_REVD,
    TCP_STATUS_SYN_SENT,
    TCP_STATUS_ESTABLISHED,
    TCP_STATUS_FIN_WAIT_1,
    TCP_STATUS_FIN_WAIT_2,
    TCP_STATUS_CLOSING,
    TCP_STATUS_TIME_WAIT,
    TCP_STATUS_CLOSE_WAIT,
    TCP_STATUS_LAST_ACK
}cp;//控制状态机

#define TCP_CWR_FLAG         0x80
#define TCP_ECE_FLAG         0x40
#define TCP_URG_FLAG         0x20
#define TCP_ACK_FLAG         0x10
#define TCP_PSH_FLAG         0x08//通知应用程序赶紧接受
#define TCP_RST_FLAG         0x04//
#define TCP_SYN_FLAG         0x02
#define TCP_FIN_FLAG         0x01

struct ntcb{
    unsigned int sip;
    unsigned int dip;
    unsigned short sport;
    unsigned short dport;
    //这里没有写具体协议

    unsigned char smac[ETH_ADDR_LENGTH];
    unsigned char dmac[ETH_ADDR_LENGTH];//一般放在arp表里面的

    unsigned char status;
    //没有定义sendbuffer;
};

int str2mac(unsigned char *mac,char *str) {

	char *p = str;
	unsigned char value = 0x0;
	int i = 0;

	while (*p != '') {
		
		if (*p == ':') {
			mac[i++] = value;
			value = 0x0;
		} else {
			
			unsigned char temp = *p;
			if (temp <= '9' && temp >= '0') {
				temp -= '0';
			} else if (temp <= 'f' && temp >= 'a') {
				temp -= 'a';
				temp += 10;
			} else if (temp <= 'F' && temp >= 'A') {
				temp -= 'A';
				temp += 10;
			} else {	
				break;
			}
			value <<= 4;
			value |= temp;
		}
		p ++;
	}

	mac[i] = value;

	return 0;
}

void echo_arp_pkt(struct arppkt *arp,struct arppkt *arp_rt,char *mac){//组织arp的回复包
    memcpy(arp_rt , arp, sizeof(struct arppkt));
    memcpy(arp_rt->eh.h_dst, arp->eh.h_src, ETH_ADDR_LENGTH);
    str2mac(arp_rt->eh.h_src, mac);
    arp_rt->eh.h_proto = arp->eh.h_proto;

    arp_rt->arp.h_addrlen = 6;
    arp_rt->arp.h_protolen= 4;
    arp_rt->arp.oper = htons(2);

    str2mac(arp_rt->arp.smac, mac);
    arp_rt->arp.sip = arp->arp.dip;

    memcpy(arp_rt->arp.dmac, arp->arp.smac, ETH_ADDR_LENGTH);
    arp_rt->arp.dip = arp->arp.sip;
}

void echo_icmp_pkt(struct icmppkt *icmp,struct icmppkt *icmp_rt){
    memcpy(icmp_rt , icmp, sizeof(struct icmppkt));
    memcpy(icmp_rt->eh.h_dst, icmp->eh.h_src, ETH_ADDR_LENGTH);
    memcpy(icmp_rt->eh.h_src, icmp->eh.h_dst, ETH_ADDR_LENGTH);

    icmp_rt->ip.dip = icmp->ip.sip;
    icmp_rt->ip.sip = icmp->ip.dip;


    icmp_rt->icmp.type = 0;
    icmp_rt->icmp.code = 0;

}

int main(){
    int tcp_buff_len = 0;
    struct nm_pkthdr h;
    struct nm_desc *nmr = nm_open("netmap:eth0",NULL,0,NULL);
    if(nmr == NULL)return -1;

    struct pollfd pfd = {0};
    pfd.fd = nmr->fd;
    pfd.events = POLLIN;

    struct ntcb tcb;
    tcb.status = TCP_STATUS_LISTEN;

    while (1)
    {
        int ret = poll(&pfd,1,-1);
        if(ret < 0)continue;

        if(pfd.revents & POLLIN){
            unsigned char *stream = nm_nextpkt(nmr,&h);//将网卡接收到的不同帧组成的ringbuffer地址

            struct ethhdr *eh = (struct ethhdr *)stream;//强转为以太网头
            if(ntohs(eh->h_proto) == PROTO_IP){
                struct udppkt *udp = (struct udppkt *)stream;

                if(udp->ip.type == PROTO_UDP){//这个
                    int udplength = ntohs(udp->udp.length);

                    udp->data[udplength-8] = '';//去掉头的数据的总长度

                    printf("udp --> %sn",udp->data);
                }else if(udp->ip.type == PROTO_ICMP){//这个协议可以使得ping命令得以实现
                    struct icmppkt *icmp = (struct icmppkt *)stream;

                    struct icmppkt icmp_rt;
                    echo_icmp_pkt(icmp,&icmp_rt);
                    nm_inject(nmr, &icmp_rt, sizeof(icmp_rt));
                    printf("n-----------ICMP已回发----------- n");
                }else if(udp->ip.type == PROTO_TCP){//1h12min处+1.20

                    struct tcppkt *tcp = (struct tcppkt *)stream;
                    
/*                  
                    unsigned int sip = tcp->ip.sip;
                    unsigned int dip = tcp->ip.dip;

                    unsigned short sport = tcp->tcp.sport;
                    unsigned short dport = tcp->tcp.dport;
                    search_tcb();....
                    //方便定位tcb,寻找对应的tcb,这里忽略了寻找tcb的过程,假定已经找到了tcb
*/                  
                    struct tcppkt tcp_rt;
                    if(tcb.status == TCP_STATUS_LISTEN){//必须有监听端
                        if(tcp->tcp.flag & TCP_SYN_FLAG){
                             tcb.status = TCP_STATUS_SYN_REVD;
                            //send syn+ack
                            memcpy(&tcp_rt , tcp, sizeof(struct tcppkt));
                            memcpy(tcp_rt.eh.h_dst, tcp->eh.h_src, ETH_ADDR_LENGTH);
                            memcpy(tcp_rt.eh.h_src, tcp->eh.h_dst, ETH_ADDR_LENGTH);
                            tcp_rt.ip.sip   = tcp->ip.dip;
                            tcp_rt.ip.dip   = tcp->ip.sip;
                            tcp_rt.tcp.acknum = htonl(tcp->tcp.seqnum+1);
                            tcp_rt.tcp.seqnum = htons(0);
                            tcp_rt.tcp.dport = tcp->tcp.sport;
                            tcp_rt.tcp.sport = tcp->tcp.dport;
                            tcp_rt.ip.totlen = j;
                            tcp_rt.tcp.flag  = (TCP_SYN_FLAG | TCP_ACK_FLAG);
                            printf("---------------TCP RECV--------------");
                            nm_inject(nmr, &tcp_rt, sizeof(tcp_rt));
                        }
                    }else if(tcb.status == TCP_STATUS_SYN_REVD){
                        if(tcp->tcp.flag & TCP_ACK_FLAG){
                            tcb.status = TCP_STATUS_ESTABLISHED;
                        }
                    }
                }
            }else if(ntohs(eh->h_proto) == PROTO_ARP){
                struct arppkt *arp = (struct arppkt *)stream;

                struct arppkt arp_rt;

                //if(arp->arp.dip == inet_addr("192.168.65.3")){
                    echo_arp_pkt(arp,&arp_rt,(char *)"00:0c:29:e9:79:2c");

                    nm_inject(nmr, &arp_rt, sizeof(arp_rt));//发出arp响应
                    printf("n-----------ARP已回发----------- n");
                //}

            }
        }
    }
    return 1;

}

         具体的测试建议Assist以及wireshark进行包的分析,得到正确的协议栈功能。

最后

以上就是单身河马为你收集整理的网络协议栈的全部内容,希望文章能够帮你解决网络协议栈所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部