#ifdef __WIN32__ #include #include #endif #include #include #include #include #include /* Compile with: gcc -O2 nfsu2relay.c -o nfsu2relay For cygwin: gcc -O2 nfsu2relay.c -o nfsu2relay -lws2_32 -mno-cygwin Usage: see http://www.csc.liv.ac.uk/~greg/nfsu2relay.html */ #ifdef __WIN32__ #pragma pack(1) struct iphdr { unsigned char ihl:4, version:4; unsigned char tos; unsigned short int tot_len; unsigned short int id; unsigned short int frag_off; unsigned char ttl; unsigned char protocol; unsigned short int check; unsigned int saddr; unsigned int daddr; /*The options start here. */ }; struct udphdr { unsigned short uh_sport; unsigned short uh_dport; unsigned short uh_ulen; unsigned short uh_sum; }; #else #include /* these headers are for a Linux system, but */ #include /* the names on other systems are easy to guess.. */ #include #include #define __FAVOR_BSD /* use bsd'ish udp header */ #include #include #endif unsigned short in_cksum(unsigned short *ptr, int nbytes) { register long sum; u_short oddbyte; register u_short answer; sum = 0; while(nbytes > 1) { sum += *ptr++; nbytes -= 2; } if(nbytes == 1) { oddbyte = 0; *((u_char *) &oddbyte) = *(u_char *)ptr; sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } /* define the pseudohdr */ struct pseudohdr { /* for creating the checksums */ unsigned long saddr; unsigned long daddr; char useless; unsigned char protocol; unsigned short length; }; ssize_t udpsend(u_int saddr, u_int daddr, unsigned short sport, unsigned short dport, char *data, unsigned short datalen) { struct sockaddr_in servaddr; struct iphdr *ip; struct udphdr *udp; struct pseudohdr *pseudo; char packet[sizeof(struct iphdr)+sizeof(struct udphdr)+datalen]; int nbytes, sockfd, on = 1; sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if(sockfd < 0) { fprintf(stderr,"cannt creat socket\n"); return(0); } if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, (void *)&on, sizeof(on)) == -1) { fprintf(stderr, "cannot setsockopt\n"); return(0); } /*if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) == -1) { printf("[socket_broadcast] can't set SO_BROADCAST option\n"); // non fatal error }*/ memset(packet, 0x00, sizeof(packet)); memcpy(packet+sizeof(struct iphdr)+sizeof(struct udphdr), data, datalen); servaddr.sin_addr.s_addr = daddr; servaddr.sin_port = htons(dport); servaddr.sin_family = AF_INET; ip = (struct iphdr *)packet; udp = (struct udphdr *)(packet + sizeof(struct iphdr)); pseudo = (struct pseudohdr *)(packet + sizeof(struct iphdr) - sizeof(struct pseudohdr)); udp->uh_sport = htons(sport); udp->uh_dport = htons(dport); udp->uh_sum = 0; udp->uh_ulen = htons(sizeof(struct udphdr)+datalen); pseudo->saddr = saddr; pseudo->daddr = daddr; pseudo->useless = 0; pseudo->protocol = IPPROTO_UDP; pseudo->length = udp->uh_ulen; udp->uh_sum = in_cksum((u_short *)pseudo,sizeof(struct udphdr)+sizeof(struct pseudohdr)+datalen); ip->ihl = 5; ip->version = 4; ip->tos = 0x10; ip->tot_len = sizeof(packet); ip->frag_off = 0; ip->ttl = 69; ip->protocol = IPPROTO_UDP; ip->check = 0; ip->saddr = saddr; ip->daddr = daddr; nbytes = sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&servaddr,sizeof(servaddr)); close(sockfd); return(nbytes); } void usage(char **argv) { fprintf(stderr,"%s [NFS machine ip...]\n",argv[0]); fprintf(stderr,"%s -e \n",argv[0]); fprintf(stderr," -e Modify behaviour to support internet routed NFS2 traffic.\n"); exit(1); } #ifdef __WIN32__ int optind = 1; char getopt(int argc, char **argv, char *parse) { if (optind >= argc) return -1; if (argv[optind][0]=='-') { if (!strcmp(argv[optind],"-e")) { optind++; return 'e'; } else { optind++; return '?'; } } return -1; } #endif int main(int argc, char **argv) { int r; char buf[BUFSIZ]; struct sockaddr_in fromaddr, thisaddr; int bindno,s; socklen_t fromlen; char option; int opt_usevpn=1; #ifdef __WIN32__ WSADATA wsaData; WSAStartup(0x0101, &wsaData); #endif while( (option=getopt(argc, argv, "e?"))!=-1 ) { //printf("%c %s\n",option, optarg ); switch( option ) { case 'e': opt_usevpn=0; break; case ':': case '?': usage(argv); break; }; } //printf("optind=%d, opt_usevpn=%d\n",optind, opt_usevpn ); if( (opt_usevpn && argc-optind<2) || (!opt_usevpn && argc!=optind+2) ) usage(argv); thisaddr.sin_family =AF_INET; thisaddr.sin_addr.s_addr=INADDR_ANY; // thisaddr.sin_addr.s_addr=inet_addr("255.255.255.255"); (fails to work on cygwin) thisaddr.sin_port=htons(9999); s=socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if( s<0 ) { fprintf(stderr,"socket() failed %d\n",s); perror(""); #ifdef __WIN32__ WSACleanup(); #endif return 0; } /* Wait for response */ if( (bindno = bind(s, (struct sockaddr *)&thisaddr, sizeof(thisaddr) ) ) < 0 ) { fprintf(stderr,"%s: errno = %d ", argv[0], errno); perror(""); fprintf(stderr,"%s: can't bind local address\n", argv[0]); perror(""); #ifdef __WIN32__ WSACleanup(); #endif return 2; } while(1) { long packetsize=0; int i; time_t t; time(&t); fromlen=sizeof(fromaddr); r=recvfrom(s, buf, BUFSIZ, 0, (struct sockaddr *)&fromaddr, &fromlen ); if( r<0 ) { fprintf(stderr,"recvfrom=%d\n", r ); perror(""); continue; } packetsize=r; printf("%d %s %d %ld %s",t, inet_ntoa(fromaddr.sin_addr), fromaddr.sin_port, packetsize, ctime(&t) ); fflush(stdout); for(i=optind;i