ip.c revision 31183
122514Sdarrenr/* 231183Speter * ip.c (C) 1995-1997 Darren Reed 322514Sdarrenr * 431183Speter * Redistribution and use in source and binary forms are permitted 531183Speter * provided that this notice is preserved and due credit is given 631183Speter * to the original author and the contributors. 722514Sdarrenr */ 831183Speter#if !defined(lint) 931183Speterstatic const char sccsid[] = "%W% %G% (C)1995"; 1031183Speterstatic const char rcsid[] = "@(#)$Id: ip.c,v 2.0.2.11 1997/10/23 11:42:44 darrenr Exp $"; 1122514Sdarrenr#endif 1222514Sdarrenr#include <errno.h> 1322514Sdarrenr#include <stdio.h> 1422514Sdarrenr#include <stdlib.h> 1522514Sdarrenr#include <unistd.h> 1622514Sdarrenr#include <string.h> 1722514Sdarrenr#include <sys/types.h> 1822514Sdarrenr#include <netinet/in_systm.h> 1922514Sdarrenr#include <sys/socket.h> 2022514Sdarrenr#include <net/if.h> 2122514Sdarrenr#include <netinet/in.h> 2222514Sdarrenr#include <netinet/ip.h> 2322514Sdarrenr#include <netinet/tcp.h> 2422514Sdarrenr#include <netinet/udp.h> 2522514Sdarrenr#include <netinet/ip_icmp.h> 2631183Speter#include <sys/param.h> 2722514Sdarrenr#ifndef linux 2831183Speter# include <netinet/if_ether.h> 2931183Speter# include <netinet/ip_var.h> 3031183Speter# if __FreeBSD_version >= 300000 3131183Speter# include <net/if_var.h> 3231183Speter# endif 3322514Sdarrenr#endif 3424583Sdarrenr#include "ipsend.h" 3522514Sdarrenr 3622514Sdarrenr 3722514Sdarrenrstatic char *ipbuf = NULL, *ethbuf = NULL; 3822514Sdarrenr 3922514Sdarrenr 4022514Sdarrenru_short chksum(buf,len) 4122514Sdarrenru_short *buf; 4222514Sdarrenrint len; 4322514Sdarrenr{ 4422514Sdarrenr u_long sum = 0; 4522514Sdarrenr int nwords = len >> 1; 4622514Sdarrenr 4722514Sdarrenr for(; nwords > 0; nwords--) 4822514Sdarrenr sum += *buf++; 4922514Sdarrenr sum = (sum>>16) + (sum & 0xffff); 5022514Sdarrenr sum += (sum >>16); 5122514Sdarrenr return (~sum); 5222514Sdarrenr} 5322514Sdarrenr 5422514Sdarrenr 5522514Sdarrenrint send_ether(nfd, buf, len, gwip) 5622514Sdarrenrint nfd, len; 5722514Sdarrenrchar *buf; 5822514Sdarrenrstruct in_addr gwip; 5922514Sdarrenr{ 6022514Sdarrenr static struct in_addr last_gw; 6122514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 6222514Sdarrenr ether_header_t *eh; 6322514Sdarrenr char *s; 6422514Sdarrenr int err; 6522514Sdarrenr 6622514Sdarrenr if (!ethbuf) 6722514Sdarrenr ethbuf = (char *)calloc(1, 65536+1024); 6822514Sdarrenr s = ethbuf; 6922514Sdarrenr eh = (ether_header_t *)s; 7022514Sdarrenr 7122514Sdarrenr bcopy((char *)buf, s + sizeof(*eh), len); 7222514Sdarrenr if (gwip.s_addr == last_gw.s_addr) 7331183Speter bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 7431183Speter else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 7522514Sdarrenr { 7622514Sdarrenr perror("arp"); 7722514Sdarrenr return -2; 7822514Sdarrenr } 7931183Speter eh->ether_type = htons(ETHERTYPE_IP); 8022514Sdarrenr last_gw.s_addr = gwip.s_addr; 8122514Sdarrenr err = sendip(nfd, s, sizeof(*eh) + len); 8222514Sdarrenr return err; 8322514Sdarrenr} 8422514Sdarrenr 8522514Sdarrenr 8622514Sdarrenr/* 8722514Sdarrenr */ 8822514Sdarrenrint send_ip(nfd, mtu, ip, gwip, frag) 8922514Sdarrenrint nfd, mtu; 9022514Sdarrenrip_t *ip; 9122514Sdarrenrstruct in_addr gwip; 9222514Sdarrenrint frag; 9322514Sdarrenr{ 9422514Sdarrenr static struct in_addr last_gw; 9522514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 9622514Sdarrenr static u_short id = 0; 9722514Sdarrenr ether_header_t *eh; 9822514Sdarrenr ip_t ipsv; 9922514Sdarrenr int err; 10022514Sdarrenr 10122514Sdarrenr if (!ipbuf) 10222514Sdarrenr ipbuf = (char *)malloc(65536); 10322514Sdarrenr eh = (ether_header_t *)ipbuf; 10422514Sdarrenr 10531183Speter bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); 10622514Sdarrenr if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 10731183Speter bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 10831183Speter else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 10922514Sdarrenr { 11022514Sdarrenr perror("arp"); 11122514Sdarrenr return -2; 11222514Sdarrenr } 11331183Speter bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp)); 11431183Speter eh->ether_type = htons(ETHERTYPE_IP); 11522514Sdarrenr 11622514Sdarrenr bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 11722514Sdarrenr last_gw.s_addr = gwip.s_addr; 11822514Sdarrenr ip->ip_len = htons(ip->ip_len); 11922514Sdarrenr ip->ip_off = htons(ip->ip_off); 12031183Speter if (!(frag & 2)) { 12131183Speter if (!ip->ip_v) 12231183Speter ip->ip_v = IPVERSION; 12331183Speter if (!ip->ip_id) 12431183Speter ip->ip_id = htons(id++); 12531183Speter if (!ip->ip_ttl) 12631183Speter ip->ip_ttl = 60; 12731183Speter } 12822514Sdarrenr 12922514Sdarrenr if (!frag || (sizeof(*eh) + ntohs(ip->ip_len) < mtu)) 13022514Sdarrenr { 13122514Sdarrenr ip->ip_sum = 0; 13224583Sdarrenr ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); 13322514Sdarrenr 13422514Sdarrenr bcopy((char *)ip, ipbuf + sizeof(*eh), ntohs(ip->ip_len)); 13522514Sdarrenr err = sendip(nfd, ipbuf, sizeof(*eh) + ntohs(ip->ip_len)); 13622514Sdarrenr } 13722514Sdarrenr else 13822514Sdarrenr { 13922514Sdarrenr /* 14022514Sdarrenr * Actually, this is bogus because we're putting all IP 14122514Sdarrenr * options in every packet, which isn't always what should be 14222514Sdarrenr * done. Will do for now. 14322514Sdarrenr */ 14422514Sdarrenr ether_header_t eth; 14522514Sdarrenr char optcpy[48], ol; 14622514Sdarrenr char *s; 14722514Sdarrenr int i, iplen, sent = 0, ts, hlen, olen; 14822514Sdarrenr 14922514Sdarrenr hlen = ip->ip_hl << 2; 15022514Sdarrenr if (mtu < (hlen + 8)) { 15122514Sdarrenr fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 15222514Sdarrenr mtu, hlen); 15322514Sdarrenr fprintf(stderr, "can't fragment data\n"); 15422514Sdarrenr return -2; 15522514Sdarrenr } 15622514Sdarrenr ol = (ip->ip_hl << 2) - sizeof(*ip); 15722514Sdarrenr for (i = 0, s = (char*)(ip + 1); ol > 0; ) 15822514Sdarrenr if (*s == IPOPT_EOL) { 15922514Sdarrenr optcpy[i++] = *s; 16022514Sdarrenr break; 16122514Sdarrenr } else if (*s == IPOPT_NOP) { 16222514Sdarrenr s++; 16322514Sdarrenr ol--; 16422514Sdarrenr } else 16522514Sdarrenr { 16622514Sdarrenr olen = (int)(*(u_char *)(s + 1)); 16722514Sdarrenr ol -= olen; 16822514Sdarrenr if (IPOPT_COPIED(*s)) 16922514Sdarrenr { 17022514Sdarrenr bcopy(s, optcpy + i, olen); 17122514Sdarrenr i += olen; 17222514Sdarrenr s += olen; 17322514Sdarrenr } 17422514Sdarrenr } 17522514Sdarrenr if (i) 17622514Sdarrenr { 17722514Sdarrenr /* 17822514Sdarrenr * pad out 17922514Sdarrenr */ 18022514Sdarrenr while ((i & 3) && (i & 3) != 3) 18122514Sdarrenr optcpy[i++] = IPOPT_NOP; 18222514Sdarrenr if ((i & 3) == 3) 18322514Sdarrenr optcpy[i++] = IPOPT_EOL; 18422514Sdarrenr } 18522514Sdarrenr 18622514Sdarrenr bcopy((char *)eh, (char *)ð, sizeof(eth)); 18722514Sdarrenr s = (char *)ip + hlen; 18822514Sdarrenr iplen = ntohs(ip->ip_len) - hlen; 18922514Sdarrenr ip->ip_off |= htons(IP_MF); 19022514Sdarrenr 19122514Sdarrenr while (1) 19222514Sdarrenr { 19322514Sdarrenr if ((sent + (mtu - hlen)) >= iplen) 19422514Sdarrenr { 19522514Sdarrenr ip->ip_off ^= htons(IP_MF); 19622514Sdarrenr ts = iplen - sent; 19722514Sdarrenr } 19822514Sdarrenr else 19922514Sdarrenr ts = (mtu - hlen); 20022514Sdarrenr ip->ip_off &= htons(0xe000); 20122514Sdarrenr ip->ip_off |= htons(sent >> 3); 20222514Sdarrenr ts += hlen; 20322514Sdarrenr ip->ip_len = htons(ts); 20422514Sdarrenr ip->ip_sum = 0; 20524583Sdarrenr ip->ip_sum = chksum((u_short *)ip, hlen); 20622514Sdarrenr bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 20722514Sdarrenr bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 20822514Sdarrenr err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 20922514Sdarrenr 21022514Sdarrenr bcopy((char *)ð, ipbuf, sizeof(eth)); 21122514Sdarrenr sent += (ts - hlen); 21222514Sdarrenr if (!(ntohs(ip->ip_off) & IP_MF)) 21322514Sdarrenr break; 21422514Sdarrenr else if (!(ip->ip_off & htons(0x1fff))) 21522514Sdarrenr { 21622514Sdarrenr hlen = i + sizeof(*ip); 21722514Sdarrenr ip->ip_hl = (sizeof(*ip) + i) >> 2; 21822514Sdarrenr bcopy(optcpy, (char *)(ip + 1), i); 21922514Sdarrenr } 22022514Sdarrenr } 22122514Sdarrenr } 22222514Sdarrenr 22322514Sdarrenr bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 22422514Sdarrenr return err; 22522514Sdarrenr} 22622514Sdarrenr 22722514Sdarrenr 22822514Sdarrenr/* 22922514Sdarrenr * send a tcp packet. 23022514Sdarrenr */ 23122514Sdarrenrint send_tcp(nfd, mtu, ip, gwip) 23222514Sdarrenrint nfd, mtu; 23322514Sdarrenrip_t *ip; 23422514Sdarrenrstruct in_addr gwip; 23522514Sdarrenr{ 23622514Sdarrenr static tcp_seq iss = 2; 23722514Sdarrenr struct tcpiphdr *ti; 23822514Sdarrenr int thlen, i; 23922514Sdarrenr u_long lbuf[20]; 24022514Sdarrenr 24122514Sdarrenr ti = (struct tcpiphdr *)lbuf; 24222514Sdarrenr bzero((char *)ti, sizeof(*ti)); 24322514Sdarrenr thlen = sizeof(tcphdr_t); 24422514Sdarrenr ip->ip_p = IPPROTO_TCP; 24522514Sdarrenr ti->ti_pr = ip->ip_p; 24622514Sdarrenr ti->ti_src = ip->ip_src; 24722514Sdarrenr ti->ti_dst = ip->ip_dst; 24822514Sdarrenr bcopy((char *)ip + (ip->ip_hl << 2), 24922514Sdarrenr (char *)&ti->ti_sport, sizeof(tcphdr_t)); 25022514Sdarrenr 25122514Sdarrenr if (!ti->ti_win) 25222514Sdarrenr ti->ti_win = htons(4096); 25322514Sdarrenr if (!ti->ti_seq) 25422514Sdarrenr ti->ti_seq = htonl(iss); 25522514Sdarrenr iss += 64; 25622514Sdarrenr 25722514Sdarrenr if ((ti->ti_flags == TH_SYN) && !ip->ip_off) 25822514Sdarrenr { 25922514Sdarrenr ip = (ip_t *)realloc((char *)ip, ntohs(ip->ip_len) + 4); 26022514Sdarrenr i = sizeof(struct tcpiphdr) / sizeof(long); 26122514Sdarrenr lbuf[i] = htonl(0x020405b4); 26222514Sdarrenr bcopy((char *)(lbuf + i), (char*)ip + ntohs(ip->ip_len), 26322514Sdarrenr sizeof(u_long)); 26422514Sdarrenr thlen += 4; 26522514Sdarrenr } 26622514Sdarrenr if (!ti->ti_off) 26722514Sdarrenr ti->ti_off = thlen >> 2; 26822514Sdarrenr ti->ti_len = htons(thlen); 26922514Sdarrenr ip->ip_len = (ip->ip_hl << 2) + thlen; 27022514Sdarrenr ti->ti_sum = 0; 27124583Sdarrenr ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 27222514Sdarrenr 27322514Sdarrenr bcopy((char *)&ti->ti_sport, 27422514Sdarrenr (char *)ip + (ip->ip_hl << 2), thlen); 27522514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 27622514Sdarrenr} 27722514Sdarrenr 27822514Sdarrenr 27922514Sdarrenr/* 28022514Sdarrenr * send a udp packet. 28122514Sdarrenr */ 28222514Sdarrenrint send_udp(nfd, mtu, ip, gwip) 28322514Sdarrenrint nfd, mtu; 28422514Sdarrenrip_t *ip; 28522514Sdarrenrstruct in_addr gwip; 28622514Sdarrenr{ 28722514Sdarrenr struct tcpiphdr *ti; 28822514Sdarrenr int thlen; 28922514Sdarrenr u_long lbuf[20]; 29022514Sdarrenr 29122514Sdarrenr ti = (struct tcpiphdr *)lbuf; 29222514Sdarrenr bzero((char *)ti, sizeof(*ti)); 29322514Sdarrenr thlen = sizeof(udphdr_t); 29422514Sdarrenr ti->ti_pr = ip->ip_p; 29522514Sdarrenr ti->ti_src = ip->ip_src; 29622514Sdarrenr ti->ti_dst = ip->ip_dst; 29722514Sdarrenr bcopy((char *)ip + (ip->ip_hl << 2), 29822514Sdarrenr (char *)&ti->ti_sport, sizeof(udphdr_t)); 29922514Sdarrenr 30022514Sdarrenr ti->ti_len = htons(thlen); 30122514Sdarrenr ip->ip_len = (ip->ip_hl << 2) + thlen; 30222514Sdarrenr ti->ti_sum = 0; 30324583Sdarrenr ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 30422514Sdarrenr 30522514Sdarrenr bcopy((char *)&ti->ti_sport, 30622514Sdarrenr (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t)); 30722514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 30822514Sdarrenr} 30922514Sdarrenr 31022514Sdarrenr 31122514Sdarrenr/* 31222514Sdarrenr * send an icmp packet. 31322514Sdarrenr */ 31422514Sdarrenrint send_icmp(nfd, mtu, ip, gwip) 31522514Sdarrenrint nfd, mtu; 31622514Sdarrenrip_t *ip; 31722514Sdarrenrstruct in_addr gwip; 31822514Sdarrenr{ 31922514Sdarrenr struct icmp *ic; 32022514Sdarrenr 32122514Sdarrenr ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); 32222514Sdarrenr 32322514Sdarrenr ic->icmp_cksum = 0; 32424583Sdarrenr ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 32522514Sdarrenr 32622514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 32722514Sdarrenr} 32822514Sdarrenr 32922514Sdarrenr 33022514Sdarrenrint send_packet(nfd, mtu, ip, gwip) 33122514Sdarrenrint nfd, mtu; 33222514Sdarrenrip_t *ip; 33322514Sdarrenrstruct in_addr gwip; 33422514Sdarrenr{ 33522514Sdarrenr switch (ip->ip_p) 33622514Sdarrenr { 33722514Sdarrenr case IPPROTO_TCP : 33822514Sdarrenr return send_tcp(nfd, mtu, ip, gwip); 33922514Sdarrenr case IPPROTO_UDP : 34022514Sdarrenr return send_udp(nfd, mtu, ip, gwip); 34122514Sdarrenr case IPPROTO_ICMP : 34222514Sdarrenr return send_icmp(nfd, mtu, ip, gwip); 34322514Sdarrenr default : 34422514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 34522514Sdarrenr } 34622514Sdarrenr} 347