实现的功能
ARP的实现
首先我们必须明白,我们的ip是自己手动设定的,这时,怎样让别人知道你,就需要ARP,也就是通过ip找mac地址
ICMP的实现
ICMP这里主要是实现了ping命令
此时ip还没有和mac地址关联
那么ping一下,发现了设备
此时,ip和mac关联了
具体操作
通过发送广播,使设备获取到ip
然后,我们使用udp给设备发消息
![]()
那么tcp也试一下
![]()
再贴一个网络抓包
最前面三个是三次握手,然后依次是,客户端发数据,服务器应答,然后服务器发数据,客户端应答,来回两次,最后四个就是四次分手了
缺点:不能发送大堆的数据,同时没有做包效验,不过一次传输少量数据还是很不错的!!!!
具体代码实现
1.arp
unsigned int is_arp_ask_pack(unsigned char *buf) { if (buf[ETH_ARP_OPCODE_H_P] == 0x00 && buf[ETH_ARP_OPCODE_L_P] == 0x01) { /*请求包*/ if (0 == memcmp(get_arp_dst_ip(buf),ipaddr,4)) { //请求的我的ip return 1; } } return 0; } //回发响应包,通过ip找mac void make_arp_answer_from_request(unsigned char *buf) { unsigned char i=0; //填写包的目的MAC地址以及源MAC地址 make_eth(buf); //填写ARP响应包的类型 buf[ETH_ARP_OPCODE_H_P]=ETH_ARP_OPCODE_REPLY_H_V; //arp 响应 buf[ETH_ARP_OPCODE_L_P]=ETH_ARP_OPCODE_REPLY_L_V; //填写ARP包的目的MAC地址以及源MAC地址 while(i<6) { buf[ETH_ARP_DST_MAC_P+i]=buf[ETH_ARP_SRC_MAC_P+i]; buf[ETH_ARP_SRC_MAC_P+i]=macaddr[i]; i++; } //填写ARP包的目的IP地址以及源IP地址 i=0; while(i<4) { buf[ETH_ARP_DST_IP_P+i]=buf[ETH_ARP_SRC_IP_P+i]; buf[ETH_ARP_SRC_IP_P+i]=ipaddr[i]; i++; } //发送ARP相应包 enc28j60PacketSend(42,buf); }
2.ICMP
void make_echo_reply_from_request(unsigned char *buf,unsigned int len) { //填写包的目的MAC地址以及源MAC地址 make_eth(buf); //填写包的目的IP地址以及源IP地址 make_ip(buf); //填写ICMP相应包类型 buf[ICMP_TYPE_P]=ICMP_TYPE_ECHOREPLY_V; //////回送应答///// // we changed only the icmp.type field from request(=8) to reply(=0). // we can therefore easily correct the checksum: if (buf[ICMP_CHECKSUM_P] > (0xff-0x08)) { buf[ICMP_CHECKSUM_P+1]++; } buf[ICMP_CHECKSUM_P]+=0x08; //发送ICMP响应包 enc28j60PacketSend(len,buf); }
3.udp
void make_udp_reply_from_request(unsigned char *buf,unsigned int datalen) { unsigned int i=0; unsigned int ck; make_eth(buf); // total length field in the IP header must be set: i= IP_HEADER_LEN+UDP_HEADER_LEN+datalen; buf[IP_TOTLEN_H_P]=i>>8; buf[IP_TOTLEN_L_P]=i; make_ip(buf); buf[UDP_DST_PORT_H_P]=udp_dst_port >> 8;//buf[UDP_SRC_PORT_H_P]; buf[UDP_DST_PORT_L_P]=udp_dst_port & 0xff;//buf[UDP_SRC_PORT_L_P]; buf[UDP_SRC_PORT_H_P]=udp_src_port >> 8; buf[UDP_SRC_PORT_L_P]=udp_src_port & 0xff; // source port does not matter and is what the sender used. // calculte the udp length: buf[UDP_LEN_H_P]=datalen>>8; buf[UDP_LEN_L_P]=UDP_HEADER_LEN+datalen; // zero the checksum buf[UDP_CHECKSUM_H_P]=0; buf[UDP_CHECKSUM_L_P]=0; ck=checksum(&buf[IP_SRC_P], 16 + datalen,1); buf[UDP_CHECKSUM_H_P]=ck >> 8; buf[UDP_CHECKSUM_L_P]=ck & 0xff; enc28j60PacketSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen,buf); }
3.TCP
void make_tcphead(unsigned char *buf,unsigned char mss/*设置mss选项*/) { buf[TCP_DST_PORT_H_P]=tcp_dst_port >> 8; buf[TCP_DST_PORT_L_P]=tcp_dst_port & 0xff; buf[TCP_SRC_PORT_H_P]=tcp_src_port >> 8; buf[TCP_SRC_PORT_L_P]=tcp_src_port & 0xff; put_int_to_char(&buf[TCP_SEQ_H_P],seqnum); put_int_to_char(&buf[TCP_SEQACK_H_P],asknum); // zero the checksum buf[TCP_CHECKSUM_H_P]=0; buf[TCP_CHECKSUM_L_P]=0; // The tcp header length is only a 4 bit field (the upper 4 bits). // It is calculated in units of 4 bytes. // E.g 24 bytes: 24/4=6 => 0x60=header len field //buf[TCP_HEADER_LEN_P]=(((TCP_HEADER_LEN_PLAIN+4)/4)) <<4; // 0x60 if (mss) { // the only option we set is MSS to 1408: // 1408 in hex is 0x580 buf[TCP_OPTIONS_P]=2; buf[TCP_OPTIONS_P+1]=4; buf[TCP_OPTIONS_P+2]=0x05; buf[TCP_OPTIONS_P+3]=0x80; // 24 bytes: buf[TCP_HEADER_LEN_P]=0x60; } else { // no options: // 20 bytes: buf[TCP_HEADER_LEN_P]=0x50; } } //连接三次握手时,第二次连接 void make_tcp_synack_from_syn(unsigned char *buf) { unsigned int ck; //填写包的目的MAC地址以及源MAC地址 make_eth(buf); //计算包的长度 // total length field in the IP header must be set: 20 bytes IP + 24 bytes (20tcp+4tcp options) ck = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4; buf[IP_TOTLEN_H_P]=ck >> 8; buf[IP_TOTLEN_L_P]=ck & 0xff; //填写包的目的IP地址以及源IP地址 make_ip(buf); buf[TCP_FLAGS_P]=TCP_FLAGS_SYNACK_V;//SYN ACK make_tcphead(buf,1/*同步时添加mss信息*/); // calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + 4 (one option: mss) ck=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+4,2); buf[TCP_CHECKSUM_H_P]=ck>>8; buf[TCP_CHECKSUM_L_P]=ck& 0xff; // add 4 for option mss: enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN,buf); } //应答包,没有数据 void make_tcp_ack_from_any(unsigned char *buf,unsigned int len/*上个包的数据长度*/) { unsigned int j; make_eth(buf); // fill the header: buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V; //ASK // if there is no data then we must still acknoledge one packet make_tcphead(buf,0); // no options // total length field in the IP header must be set: // 20 bytes IP + 20 bytes tcp (when no options) j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN; buf[IP_TOTLEN_H_P]=j>>8; buf[IP_TOTLEN_L_P]=j&0xff; make_ip(buf); // calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2); buf[TCP_CHECKSUM_H_P]=j>>8; buf[TCP_CHECKSUM_L_P]=j&0xff; //printf("\n\r神舟III号[%d.%d.%d.%d]发送ACK包响应",ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]); enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf); } //此函数必须确保,在make_tcp_ack_from_any()之后调用 void make_tcp_ack_with_data(unsigned char *buf,unsigned int dlen) { unsigned int j; // fill the header: // This code requires that we send only one data packet // because we keep no state information. We must therefore set // the fin here: buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V/*有数据*/; make_tcphead(buf,0); // total length field in the IP header must be set: // 20 bytes IP + 20 bytes tcp (when no options) + len of data j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen; buf[IP_TOTLEN_H_P]=j>>8; buf[IP_TOTLEN_L_P]=j&0xff; fill_ip_hdr_checksum(buf); // zero the checksum buf[TCP_CHECKSUM_H_P]=0; buf[TCP_CHECKSUM_L_P]=0; // calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN+dlen,2); buf[TCP_CHECKSUM_H_P]=j>>8; buf[TCP_CHECKSUM_L_P]=j& 0xff; enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN,buf); } //此函数必须确保,在make_tcp_ack_from_any()之后调用 void make_tcp_ack_from_finish(unsigned char *buf) { unsigned int j; // fill the header: // This code requires that we send only one data packet // because we keep no state information. We must therefore set // the fin here: buf[TCP_FLAGS_P]=TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V; // total length field in the IP header must be set: // 20 bytes IP + 20 bytes tcp (when no options) + len of data j=IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN; buf[IP_TOTLEN_H_P]=j>>8; buf[IP_TOTLEN_L_P]=j&0xff; fill_ip_hdr_checksum(buf); // zero the checksum buf[TCP_CHECKSUM_H_P]=0; buf[TCP_CHECKSUM_L_P]=0; // calculate the checksum, len=8 (start from ip.src) + TCP_HEADER_LEN_PLAIN + data len j=checksum(&buf[IP_SRC_P], 8+TCP_HEADER_LEN_PLAIN,2); buf[TCP_CHECKSUM_H_P]=j>>8; buf[TCP_CHECKSUM_L_P]=j& 0xff; enc28j60PacketSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN,buf); } unsigned int check_tcp_udp(unsigned char *buf,unsigned int len) { switch(check_packet_type(buf,len)) { case TYPE_ARP: //printf("this is a arp\n"); if (is_arp_ask_pack(buf)) { // printf("arp:src-->[%d.%d.%d.%d]\n",get_arp_src_ip(buf)[0],get_arp_src_ip(buf)[1], // get_arp_src_ip(buf)[2],get_arp_src_ip(buf)[3]); // printf("arp:dst-->[%d.%d.%d.%d]\n",get_arp_dst_ip(buf)[0],get_arp_dst_ip(buf)[1], // get_arp_dst_ip(buf)[2],get_arp_dst_ip(buf)[3]); make_arp_answer_from_request(buf); } break; case TYPE_ICMP: //printf("this is a icmp\n"); if (is_icmp_ask_pack(buf)) { make_echo_reply_from_request(buf,len); } break; case TYPE_TCP: //printf("this is a tcp\n"); return 1; case TYPE_UDP: //printf("this is a udp\n"); return 1; case TYPE_NONE: default: } return 0; }
好了,此程序根据神州III源程序更改而成,去除了http协议