ip.c revision 24583
122514Sdarrenr/* 222514Sdarrenr * ip.c (C) 1995 Darren Reed 322514Sdarrenr * 422514Sdarrenr * The author provides this program as-is, with no gaurantee for its 522514Sdarrenr * suitability for any specific purpose. The author takes no responsibility 622514Sdarrenr * for the misuse/abuse of this program and provides it for the sole purpose 722514Sdarrenr * of testing packet filter policies. This file maybe distributed freely 822514Sdarrenr * providing it is not modified and that this notice remains in tact. 922514Sdarrenr */ 1022514Sdarrenr#if !defined(lint) && defined(LIBC_SCCS) 1122514Sdarrenrstatic char sccsid[] = "%W% %G% (C)1995"; 1222514Sdarrenr#endif 1322514Sdarrenr#include <errno.h> 1422514Sdarrenr#include <stdio.h> 1522514Sdarrenr#include <stdlib.h> 1622514Sdarrenr#include <unistd.h> 1722514Sdarrenr#include <string.h> 1822514Sdarrenr#include <sys/types.h> 1922514Sdarrenr#include <netinet/in_systm.h> 2022514Sdarrenr#include <sys/socket.h> 2122514Sdarrenr#include <net/if.h> 2222514Sdarrenr#include <netinet/in.h> 2322514Sdarrenr#include <netinet/ip.h> 2422514Sdarrenr#include <netinet/tcp.h> 2522514Sdarrenr#include <netinet/udp.h> 2622514Sdarrenr#include <netinet/ip_icmp.h> 2722514Sdarrenr#ifndef linux 2822514Sdarrenr#include <netinet/if_ether.h> 2922514Sdarrenr#include <netinet/ip_var.h> 3022514Sdarrenr#endif 3124583Sdarrenr#include "ipsend.h" 3222514Sdarrenr 3322514Sdarrenr 3422514Sdarrenrstatic char *ipbuf = NULL, *ethbuf = NULL; 3522514Sdarrenr 3622514Sdarrenr 3722514Sdarrenru_short chksum(buf,len) 3822514Sdarrenru_short *buf; 3922514Sdarrenrint len; 4022514Sdarrenr{ 4122514Sdarrenr u_long sum = 0; 4222514Sdarrenr int nwords = len >> 1; 4322514Sdarrenr 4422514Sdarrenr for(; nwords > 0; nwords--) 4522514Sdarrenr sum += *buf++; 4622514Sdarrenr sum = (sum>>16) + (sum & 0xffff); 4722514Sdarrenr sum += (sum >>16); 4822514Sdarrenr return (~sum); 4922514Sdarrenr} 5022514Sdarrenr 5122514Sdarrenr 5222514Sdarrenrint send_ether(nfd, buf, len, gwip) 5322514Sdarrenrint nfd, len; 5422514Sdarrenrchar *buf; 5522514Sdarrenrstruct in_addr gwip; 5622514Sdarrenr{ 5722514Sdarrenr static struct in_addr last_gw; 5822514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 5922514Sdarrenr ether_header_t *eh; 6022514Sdarrenr char *s; 6122514Sdarrenr int err; 6222514Sdarrenr 6322514Sdarrenr if (!ethbuf) 6422514Sdarrenr ethbuf = (char *)calloc(1, 65536+1024); 6522514Sdarrenr s = ethbuf; 6622514Sdarrenr eh = (ether_header_t *)s; 6722514Sdarrenr 6822514Sdarrenr bcopy((char *)buf, s + sizeof(*eh), len); 6922514Sdarrenr if (gwip.s_addr == last_gw.s_addr) 7022514Sdarrenr bcopy(last_arp, (char *)&eh->ether_dhost, 6); 7124583Sdarrenr else if (arp((char *)&gwip, (char *)&eh->ether_dhost) == -1) 7222514Sdarrenr { 7322514Sdarrenr perror("arp"); 7422514Sdarrenr return -2; 7522514Sdarrenr } 7622514Sdarrenr eh->ether_type = ETHERTYPE_IP; 7722514Sdarrenr last_gw.s_addr = gwip.s_addr; 7822514Sdarrenr err = sendip(nfd, s, sizeof(*eh) + len); 7922514Sdarrenr return err; 8022514Sdarrenr} 8122514Sdarrenr 8222514Sdarrenr 8322514Sdarrenr/* 8422514Sdarrenr */ 8522514Sdarrenrint send_ip(nfd, mtu, ip, gwip, frag) 8622514Sdarrenrint nfd, mtu; 8722514Sdarrenrip_t *ip; 8822514Sdarrenrstruct in_addr gwip; 8922514Sdarrenrint frag; 9022514Sdarrenr{ 9122514Sdarrenr static struct in_addr last_gw; 9222514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 9322514Sdarrenr static u_short id = 0; 9422514Sdarrenr ether_header_t *eh; 9522514Sdarrenr ip_t ipsv; 9622514Sdarrenr int err; 9722514Sdarrenr 9822514Sdarrenr if (!ipbuf) 9922514Sdarrenr ipbuf = (char *)malloc(65536); 10022514Sdarrenr eh = (ether_header_t *)ipbuf; 10122514Sdarrenr 10222514Sdarrenr bzero((char *)&eh->ether_shost, sizeof(eh->ether_shost)); 10322514Sdarrenr if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 10422514Sdarrenr bcopy(last_arp, (char *)&eh->ether_dhost, 6); 10524583Sdarrenr else if (arp((char *)&gwip, (char *)&eh->ether_dhost) == -1) 10622514Sdarrenr { 10722514Sdarrenr perror("arp"); 10822514Sdarrenr return -2; 10922514Sdarrenr } 11022514Sdarrenr bcopy((char *)&eh->ether_dhost, last_arp, sizeof(last_arp)); 11122514Sdarrenr eh->ether_type = ETHERTYPE_IP; 11222514Sdarrenr 11322514Sdarrenr bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 11422514Sdarrenr last_gw.s_addr = gwip.s_addr; 11522514Sdarrenr ip->ip_len = htons(ip->ip_len); 11622514Sdarrenr ip->ip_off = htons(ip->ip_off); 11722514Sdarrenr if (!ip->ip_v) 11822514Sdarrenr ip->ip_v = IPVERSION; 11922514Sdarrenr if (!ip->ip_id) 12022514Sdarrenr ip->ip_id = htons(id++); 12122514Sdarrenr if (!ip->ip_ttl) 12222514Sdarrenr ip->ip_ttl = 60; 12322514Sdarrenr 12422514Sdarrenr if (!frag || (sizeof(*eh) + ntohs(ip->ip_len) < mtu)) 12522514Sdarrenr { 12622514Sdarrenr ip->ip_sum = 0; 12724583Sdarrenr ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); 12822514Sdarrenr 12922514Sdarrenr bcopy((char *)ip, ipbuf + sizeof(*eh), ntohs(ip->ip_len)); 13022514Sdarrenr err = sendip(nfd, ipbuf, sizeof(*eh) + ntohs(ip->ip_len)); 13122514Sdarrenr } 13222514Sdarrenr else 13322514Sdarrenr { 13422514Sdarrenr /* 13522514Sdarrenr * Actually, this is bogus because we're putting all IP 13622514Sdarrenr * options in every packet, which isn't always what should be 13722514Sdarrenr * done. Will do for now. 13822514Sdarrenr */ 13922514Sdarrenr ether_header_t eth; 14022514Sdarrenr char optcpy[48], ol; 14122514Sdarrenr char *s; 14222514Sdarrenr int i, iplen, sent = 0, ts, hlen, olen; 14322514Sdarrenr 14422514Sdarrenr hlen = ip->ip_hl << 2; 14522514Sdarrenr if (mtu < (hlen + 8)) { 14622514Sdarrenr fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 14722514Sdarrenr mtu, hlen); 14822514Sdarrenr fprintf(stderr, "can't fragment data\n"); 14922514Sdarrenr return -2; 15022514Sdarrenr } 15122514Sdarrenr ol = (ip->ip_hl << 2) - sizeof(*ip); 15222514Sdarrenr for (i = 0, s = (char*)(ip + 1); ol > 0; ) 15322514Sdarrenr if (*s == IPOPT_EOL) { 15422514Sdarrenr optcpy[i++] = *s; 15522514Sdarrenr break; 15622514Sdarrenr } else if (*s == IPOPT_NOP) { 15722514Sdarrenr s++; 15822514Sdarrenr ol--; 15922514Sdarrenr } else 16022514Sdarrenr { 16122514Sdarrenr olen = (int)(*(u_char *)(s + 1)); 16222514Sdarrenr ol -= olen; 16322514Sdarrenr if (IPOPT_COPIED(*s)) 16422514Sdarrenr { 16522514Sdarrenr bcopy(s, optcpy + i, olen); 16622514Sdarrenr i += olen; 16722514Sdarrenr s += olen; 16822514Sdarrenr } 16922514Sdarrenr } 17022514Sdarrenr if (i) 17122514Sdarrenr { 17222514Sdarrenr /* 17322514Sdarrenr * pad out 17422514Sdarrenr */ 17522514Sdarrenr while ((i & 3) && (i & 3) != 3) 17622514Sdarrenr optcpy[i++] = IPOPT_NOP; 17722514Sdarrenr if ((i & 3) == 3) 17822514Sdarrenr optcpy[i++] = IPOPT_EOL; 17922514Sdarrenr } 18022514Sdarrenr 18122514Sdarrenr bcopy((char *)eh, (char *)ð, sizeof(eth)); 18222514Sdarrenr s = (char *)ip + hlen; 18322514Sdarrenr iplen = ntohs(ip->ip_len) - hlen; 18422514Sdarrenr ip->ip_off |= htons(IP_MF); 18522514Sdarrenr 18622514Sdarrenr while (1) 18722514Sdarrenr { 18822514Sdarrenr if ((sent + (mtu - hlen)) >= iplen) 18922514Sdarrenr { 19022514Sdarrenr ip->ip_off ^= htons(IP_MF); 19122514Sdarrenr ts = iplen - sent; 19222514Sdarrenr } 19322514Sdarrenr else 19422514Sdarrenr ts = (mtu - hlen); 19522514Sdarrenr ip->ip_off &= htons(0xe000); 19622514Sdarrenr ip->ip_off |= htons(sent >> 3); 19722514Sdarrenr ts += hlen; 19822514Sdarrenr ip->ip_len = htons(ts); 19922514Sdarrenr ip->ip_sum = 0; 20024583Sdarrenr ip->ip_sum = chksum((u_short *)ip, hlen); 20122514Sdarrenr bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 20222514Sdarrenr bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 20322514Sdarrenr err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 20422514Sdarrenr 20522514Sdarrenr bcopy((char *)ð, ipbuf, sizeof(eth)); 20622514Sdarrenr sent += (ts - hlen); 20722514Sdarrenr if (!(ntohs(ip->ip_off) & IP_MF)) 20822514Sdarrenr break; 20922514Sdarrenr else if (!(ip->ip_off & htons(0x1fff))) 21022514Sdarrenr { 21122514Sdarrenr hlen = i + sizeof(*ip); 21222514Sdarrenr ip->ip_hl = (sizeof(*ip) + i) >> 2; 21322514Sdarrenr bcopy(optcpy, (char *)(ip + 1), i); 21422514Sdarrenr } 21522514Sdarrenr } 21622514Sdarrenr } 21722514Sdarrenr 21822514Sdarrenr bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 21922514Sdarrenr return err; 22022514Sdarrenr} 22122514Sdarrenr 22222514Sdarrenr 22322514Sdarrenr/* 22422514Sdarrenr * send a tcp packet. 22522514Sdarrenr */ 22622514Sdarrenrint send_tcp(nfd, mtu, ip, gwip) 22722514Sdarrenrint nfd, mtu; 22822514Sdarrenrip_t *ip; 22922514Sdarrenrstruct in_addr gwip; 23022514Sdarrenr{ 23122514Sdarrenr static tcp_seq iss = 2; 23222514Sdarrenr struct tcpiphdr *ti; 23322514Sdarrenr int thlen, i; 23422514Sdarrenr u_long lbuf[20]; 23522514Sdarrenr 23622514Sdarrenr ti = (struct tcpiphdr *)lbuf; 23722514Sdarrenr bzero((char *)ti, sizeof(*ti)); 23822514Sdarrenr thlen = sizeof(tcphdr_t); 23922514Sdarrenr ip->ip_p = IPPROTO_TCP; 24022514Sdarrenr ti->ti_pr = ip->ip_p; 24122514Sdarrenr ti->ti_src = ip->ip_src; 24222514Sdarrenr ti->ti_dst = ip->ip_dst; 24322514Sdarrenr bcopy((char *)ip + (ip->ip_hl << 2), 24422514Sdarrenr (char *)&ti->ti_sport, sizeof(tcphdr_t)); 24522514Sdarrenr 24622514Sdarrenr if (!ti->ti_win) 24722514Sdarrenr ti->ti_win = htons(4096); 24822514Sdarrenr if (!ti->ti_seq) 24922514Sdarrenr ti->ti_seq = htonl(iss); 25022514Sdarrenr iss += 64; 25122514Sdarrenr 25222514Sdarrenr if ((ti->ti_flags == TH_SYN) && !ip->ip_off) 25322514Sdarrenr { 25422514Sdarrenr ip = (ip_t *)realloc((char *)ip, ntohs(ip->ip_len) + 4); 25522514Sdarrenr i = sizeof(struct tcpiphdr) / sizeof(long); 25622514Sdarrenr lbuf[i] = htonl(0x020405b4); 25722514Sdarrenr bcopy((char *)(lbuf + i), (char*)ip + ntohs(ip->ip_len), 25822514Sdarrenr sizeof(u_long)); 25922514Sdarrenr thlen += 4; 26022514Sdarrenr } 26122514Sdarrenr if (!ti->ti_off) 26222514Sdarrenr ti->ti_off = thlen >> 2; 26322514Sdarrenr ti->ti_len = htons(thlen); 26422514Sdarrenr ip->ip_len = (ip->ip_hl << 2) + thlen; 26522514Sdarrenr ti->ti_sum = 0; 26624583Sdarrenr ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 26722514Sdarrenr 26822514Sdarrenr bcopy((char *)&ti->ti_sport, 26922514Sdarrenr (char *)ip + (ip->ip_hl << 2), thlen); 27022514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 27122514Sdarrenr} 27222514Sdarrenr 27322514Sdarrenr 27422514Sdarrenr/* 27522514Sdarrenr * send a udp packet. 27622514Sdarrenr */ 27722514Sdarrenrint send_udp(nfd, mtu, ip, gwip) 27822514Sdarrenrint nfd, mtu; 27922514Sdarrenrip_t *ip; 28022514Sdarrenrstruct in_addr gwip; 28122514Sdarrenr{ 28222514Sdarrenr struct tcpiphdr *ti; 28322514Sdarrenr int thlen; 28422514Sdarrenr u_long lbuf[20]; 28522514Sdarrenr 28622514Sdarrenr ti = (struct tcpiphdr *)lbuf; 28722514Sdarrenr bzero((char *)ti, sizeof(*ti)); 28822514Sdarrenr thlen = sizeof(udphdr_t); 28922514Sdarrenr ti->ti_pr = ip->ip_p; 29022514Sdarrenr ti->ti_src = ip->ip_src; 29122514Sdarrenr ti->ti_dst = ip->ip_dst; 29222514Sdarrenr bcopy((char *)ip + (ip->ip_hl << 2), 29322514Sdarrenr (char *)&ti->ti_sport, sizeof(udphdr_t)); 29422514Sdarrenr 29522514Sdarrenr ti->ti_len = htons(thlen); 29622514Sdarrenr ip->ip_len = (ip->ip_hl << 2) + thlen; 29722514Sdarrenr ti->ti_sum = 0; 29824583Sdarrenr ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 29922514Sdarrenr 30022514Sdarrenr bcopy((char *)&ti->ti_sport, 30122514Sdarrenr (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t)); 30222514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 30322514Sdarrenr} 30422514Sdarrenr 30522514Sdarrenr 30622514Sdarrenr/* 30722514Sdarrenr * send an icmp packet. 30822514Sdarrenr */ 30922514Sdarrenrint send_icmp(nfd, mtu, ip, gwip) 31022514Sdarrenrint nfd, mtu; 31122514Sdarrenrip_t *ip; 31222514Sdarrenrstruct in_addr gwip; 31322514Sdarrenr{ 31422514Sdarrenr struct icmp *ic; 31522514Sdarrenr 31622514Sdarrenr ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); 31722514Sdarrenr 31822514Sdarrenr ic->icmp_cksum = 0; 31924583Sdarrenr ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 32022514Sdarrenr 32122514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 32222514Sdarrenr} 32322514Sdarrenr 32422514Sdarrenr 32522514Sdarrenrint send_packet(nfd, mtu, ip, gwip) 32622514Sdarrenrint nfd, mtu; 32722514Sdarrenrip_t *ip; 32822514Sdarrenrstruct in_addr gwip; 32922514Sdarrenr{ 33022514Sdarrenr switch (ip->ip_p) 33122514Sdarrenr { 33222514Sdarrenr case IPPROTO_TCP : 33322514Sdarrenr return send_tcp(nfd, mtu, ip, gwip); 33422514Sdarrenr case IPPROTO_UDP : 33522514Sdarrenr return send_udp(nfd, mtu, ip, gwip); 33622514Sdarrenr case IPPROTO_ICMP : 33722514Sdarrenr return send_icmp(nfd, mtu, ip, gwip); 33822514Sdarrenr default : 33922514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 34022514Sdarrenr } 34122514Sdarrenr} 342