//rudp-server2.c //rawsocket + sendto/recvfrom+修改头部 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <errno.h>
#define BUFLEN 4096 #define PORT 8848 typedef struct ip_hdr{ 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; }ip_hdr; typedef struct udp_hdr{ unsigned short s_port; unsigned short d_port; unsigned short length; unsigned short cksum; }udp_hdr;
typedef struct psd_header{//伪头部,用于计算校验和
unsigned int s_ip;//source ip
unsigned int d_ip;//dest ip
unsigned char mbz;//0
unsigned char proto;//proto type
unsigned short plen;//length
}psd_header;
void swap(unsigned int *a, unsigned int *b) { *a = (*a)^(*b); *b = (*a)^(*b); *a = (*a)^(*b); }
unsigned short checksum(unsigned short* buffer, int size) { unsigned long cksum = 0; while(size>1) { cksum += *buffer++; size -= sizeof(unsigned short); } if(size) { cksum += *(unsigned char*)buffer; } cksum = (cksum>>16) + (cksum&0xffff); //将高16bit与低16bit相加
cksum += (cksum>>16); //将进位到高位的16bit与低16bit 再相加
return (unsigned short)(~cksum); } int main(int argc, char *argv[]) { char revbuf[BUFLEN]; int sockfd = -1; struct sockaddr_in host_addr; if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP))<0) { printf("socket() error!\n"); exit(1); } memset(&host_addr, 0, sizeof(host_addr)); host_addr.sin_family = AF_INET; host_addr.sin_port = htons(PORT); host_addr.sin_addr.s_addr = inet_addr("200.200.30.14"); if(bind(sockfd, (struct sockaddr*)&host_addr, sizeof(host_addr))<0) { printf("error for bind()%s\n", strerror(errno)); close(sockfd); exit(1); } const int on = 1; if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))<0) { printf("setsockopt() error!\n"); exit(0); } int addr_len = sizeof(host_addr);
while(1) { int revlen=0; memset(&host_addr, 0, sizeof(host_addr)); int addr_len = sizeof(host_addr); if((revlen = recvfrom(sockfd, revbuf, BUFLEN, 0, (struct sockaddr*)&host_addr, &addr_len))<0) { printf("recvfrom() error!\n"); close(sockfd); exit(1); }else{ udp_hdr *udphdr; udphdr = (udp_hdr*)(revbuf+20); if(udphdr->d_port^htons(PORT)) continue; printf("receive from %s:%d\n", inet_ntoa(host_addr.sin_addr), ntohs(host_addr.sin_port)); struct sockaddr_in name; int len; getsockname(sockfd, (struct sockaddr*)&name, &len); printf("sockname %s:%d\n", inet_ntoa(name.sin_addr), ntohs(name.sin_port)); memset(&name, 0, sizeof(name)); getpeername(sockfd, (struct sockaddr*)&name, &len); printf("peername %s:%u\n", inet_ntoa(name.sin_addr), ntohs(name.sin_port)); ip_hdr *iphdr; iphdr = (ip_hdr*)revbuf; udp_hdr *udphdr1; udphdr1 = (udp_hdr*)(revbuf+20); swap(&(iphdr->ip_source), &(iphdr->ip_dest)); unsigned short t = udphdr1->s_port; udphdr1->s_port = udphdr1->d_port; udphdr1->d_port = htons(ntohs(t)+1); char tmp4[ntohs(udphdr1->length)+sizeof(psd_header)]; psd_header* ph = (psd_header*)tmp4; ph->d_ip=iphdr->ip_dest; ph->s_ip=iphdr->ip_source; ph->mbz=0; ph->proto = 0x11; ph->plen = udphdr1->length; //printf("udp header length %d\n", ntohs(udphdr1->length));
memcpy((unsigned char*)ph+sizeof(psd_header), (unsigned char*)udphdr1, ntohs(udphdr1->length)); udphdr1->cksum = 0; udphdr1->cksum = checksum((unsigned short*)(ph), ntohs(udphdr1->length)+sizeof(psd_header)); printf("totallen %d bytes\n", ntohs(iphdr->ip_total_length)); } if(sendto(sockfd, revbuf, revlen, 0, (struct sockaddr*)&host_addr, sizeof(host_addr))!=revlen) { printf("sendto() error, %s\n", strerror(errno)); close(sockfd)%
|