ip.c revision 92686
154359Sroberto/* 2132451Sroberto * ip.c (C) 1995-1998 Darren Reed 354359Sroberto * 454359Sroberto * See the IPFILTER.LICENCE file for details on licencing. 554359Sroberto */ 654359Sroberto#ifdef __sgi 754359Sroberto# include <sys/ptimers.h> 854359Sroberto#endif 954359Sroberto#include <errno.h> 1054359Sroberto#include <stdio.h> 1154359Sroberto#include <stdlib.h> 1254359Sroberto#include <unistd.h> 13285612Sdelphij#include <string.h> 1454359Sroberto#include <sys/types.h> 15285612Sdelphij#include <netinet/in_systm.h> 1654359Sroberto#include <sys/socket.h> 1754359Sroberto#include <net/if.h> 1854359Sroberto#include <netinet/in.h> 19132451Sroberto#include <netinet/ip.h> 2054359Sroberto#include <netinet/tcp.h> 21132451Sroberto#include <netinet/udp.h> 2254359Sroberto#include <netinet/ip_icmp.h> 2354359Sroberto#include <sys/param.h> 2454359Sroberto#ifndef linux 2554359Sroberto# include <netinet/if_ether.h> 2654359Sroberto# include <netinet/ip_var.h> 27132451Sroberto# if __FreeBSD_version >= 300000 28132451Sroberto# include <net/if_var.h> 29132451Sroberto# endif 30132451Sroberto#endif 31132451Sroberto#include "ipsend.h" 32132451Sroberto 3354359Sroberto#if !defined(lint) 3454359Srobertostatic const char sccsid[] = "%W% %G% (C)1995"; 35132451Srobertostatic const char rcsid[] = "@(#)$Id: ip.c,v 2.1.4.4 2002/02/22 15:32:57 darrenr Exp $"; 36132451Sroberto#endif 37132451Sroberto 38132451Srobertostatic char *ipbuf = NULL, *ethbuf = NULL; 39132451Sroberto 4054359Sroberto 41132451Srobertou_short chksum(buf,len) 42132451Srobertou_short *buf; 43132451Srobertoint len; 44132451Sroberto{ 45132451Sroberto u_long sum = 0; 46285612Sdelphij int nwords = len >> 1; 47285612Sdelphij 48285612Sdelphij for(; nwords > 0; nwords--) 49285612Sdelphij sum += *buf++; 50285612Sdelphij sum = (sum>>16) + (sum & 0xffff); 51285612Sdelphij sum += (sum >>16); 52285612Sdelphij return (~sum); 53132451Sroberto} 5454359Sroberto 5554359Sroberto 56285612Sdelphijint send_ether(nfd, buf, len, gwip) 57285612Sdelphijint nfd, len; 58285612Sdelphijchar *buf; 5954359Srobertostruct in_addr gwip; 60285612Sdelphij{ 61285612Sdelphij static struct in_addr last_gw; 6254359Sroberto static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 6354359Sroberto ether_header_t *eh; 6454359Sroberto char *s; 6554359Sroberto int err; 66285612Sdelphij 67285612Sdelphij if (!ethbuf) 68285612Sdelphij ethbuf = (char *)calloc(1, 65536+1024); 6954359Sroberto s = ethbuf; 7054359Sroberto eh = (ether_header_t *)s; 7154359Sroberto 7254359Sroberto bcopy((char *)buf, s + sizeof(*eh), len); 7354359Sroberto if (gwip.s_addr == last_gw.s_addr) 74285612Sdelphij bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 75285612Sdelphij else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 7654359Sroberto { 77285612Sdelphij perror("arp"); 78285612Sdelphij return -2; 79285612Sdelphij } 8054359Sroberto eh->ether_type = htons(ETHERTYPE_IP); 8154359Sroberto last_gw.s_addr = gwip.s_addr; 82285612Sdelphij err = sendip(nfd, s, sizeof(*eh) + len); 83285612Sdelphij return err; 8454359Sroberto} 85285612Sdelphij 86132451Sroberto 8754359Sroberto/* 88285612Sdelphij */ 89330567Sgordonint send_ip(nfd, mtu, ip, gwip, frag) 90330567Sgordonint nfd, mtu; 9154359Srobertoip_t *ip; 92285612Sdelphijstruct in_addr gwip; 93285612Sdelphijint frag; 9454359Sroberto{ 9554359Sroberto static struct in_addr last_gw; 96285612Sdelphij static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 9754359Sroberto static u_short id = 0; 98285612Sdelphij ether_header_t *eh; 99330567Sgordon ip_t ipsv; 100285612Sdelphij int err, iplen; 101330567Sgordon 10254359Sroberto if (!ipbuf) 10354359Sroberto { 104285612Sdelphij ipbuf = (char *)malloc(65536); 105285612Sdelphij if(!ipbuf) 106285612Sdelphij { 107285612Sdelphij perror("malloc failed"); 108285612Sdelphij return -2; 109285612Sdelphij } 110285612Sdelphij } 111285612Sdelphij 112285612Sdelphij eh = (ether_header_t *)ipbuf; 113285612Sdelphij 114285612Sdelphij bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); 115285612Sdelphij if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 116285612Sdelphij bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 117330567Sgordon else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 118285612Sdelphij { 119285612Sdelphij perror("arp"); 120330567Sgordon return -2; 121330567Sgordon } 122285612Sdelphij bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp)); 123330567Sgordon eh->ether_type = htons(ETHERTYPE_IP); 124330567Sgordon 125330567Sgordon bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 126330567Sgordon last_gw.s_addr = gwip.s_addr; 127330567Sgordon iplen = ip->ip_len; 128330567Sgordon ip->ip_len = htons(iplen); 129330567Sgordon if (!(frag & 2)) { 130330567Sgordon if (!ip->ip_v) 131330567Sgordon ip->ip_v = IPVERSION; 132330567Sgordon if (!ip->ip_id) 133330567Sgordon ip->ip_id = htons(id++); 134330567Sgordon if (!ip->ip_ttl) 135330567Sgordon ip->ip_ttl = 60; 136330567Sgordon } 137330567Sgordon 138330567Sgordon if (!frag || (sizeof(*eh) + iplen < mtu)) 139330567Sgordon { 140330567Sgordon ip->ip_sum = 0; 141330567Sgordon ip->ip_sum = chksum((u_short *)ip, ip->ip_hl << 2); 142330567Sgordon 143330567Sgordon bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); 144330567Sgordon err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); 145330567Sgordon } 146330567Sgordon else 147330567Sgordon { 148330567Sgordon /* 149330567Sgordon * Actually, this is bogus because we're putting all IP 150330567Sgordon * options in every packet, which isn't always what should be 151330567Sgordon * done. Will do for now. 152330567Sgordon */ 153330567Sgordon ether_header_t eth; 154330567Sgordon char optcpy[48], ol; 155330567Sgordon char *s; 156330567Sgordon int i, sent = 0, ts, hlen, olen; 157330567Sgordon 158330567Sgordon hlen = ip->ip_hl << 2; 159330567Sgordon if (mtu < (hlen + 8)) { 160330567Sgordon fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 161330567Sgordon mtu, hlen); 162330567Sgordon fprintf(stderr, "can't fragment data\n"); 163330567Sgordon return -2; 164330567Sgordon } 165330567Sgordon ol = (ip->ip_hl << 2) - sizeof(*ip); 166330567Sgordon for (i = 0, s = (char*)(ip + 1); ol > 0; ) 167330567Sgordon if (*s == IPOPT_EOL) { 168330567Sgordon optcpy[i++] = *s; 169330567Sgordon break; 170330567Sgordon } else if (*s == IPOPT_NOP) { 171330567Sgordon s++; 172330567Sgordon ol--; 173330567Sgordon } else 174330567Sgordon { 175330567Sgordon olen = (int)(*(u_char *)(s + 1)); 176330567Sgordon ol -= olen; 177330567Sgordon if (IPOPT_COPIED(*s)) 178330567Sgordon { 179330567Sgordon bcopy(s, optcpy + i, olen); 180330567Sgordon i += olen; 181330567Sgordon s += olen; 182330567Sgordon } 183330567Sgordon } 184330567Sgordon if (i) 185330567Sgordon { 186330567Sgordon /* 187330567Sgordon * pad out 188330567Sgordon */ 189330567Sgordon while ((i & 3) && (i & 3) != 3) 190330567Sgordon optcpy[i++] = IPOPT_NOP; 191330567Sgordon if ((i & 3) == 3) 192330567Sgordon optcpy[i++] = IPOPT_EOL; 19354359Sroberto } 19454359Sroberto 19554359Sroberto bcopy((char *)eh, (char *)ð, sizeof(eth)); 19654359Sroberto s = (char *)ip + hlen; 19754359Sroberto iplen = ntohs(ip->ip_len) - hlen; 19854359Sroberto ip->ip_off |= htons(IP_MF); 199285612Sdelphij 200285612Sdelphij while (1) 201285612Sdelphij { 202285612Sdelphij if ((sent + (mtu - hlen)) >= iplen) 203285612Sdelphij { 204285612Sdelphij ip->ip_off ^= htons(IP_MF); 205285612Sdelphij ts = iplen - sent; 206285612Sdelphij } 207285612Sdelphij else 208285612Sdelphij ts = (mtu - hlen); 209285612Sdelphij ip->ip_off &= htons(0xe000); 210285612Sdelphij ip->ip_off |= htons(sent >> 3); 211285612Sdelphij ts += hlen; 212285612Sdelphij ip->ip_len = htons(ts); 213285612Sdelphij ip->ip_sum = 0; 214285612Sdelphij ip->ip_sum = chksum((u_short *)ip, hlen); 215285612Sdelphij bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 216285612Sdelphij bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 217285612Sdelphij err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 218285612Sdelphij 219285612Sdelphij bcopy((char *)ð, ipbuf, sizeof(eth)); 220285612Sdelphij sent += (ts - hlen); 221285612Sdelphij if (!(ntohs(ip->ip_off) & IP_MF)) 222285612Sdelphij break; 223285612Sdelphij else if (!(ip->ip_off & htons(0x1fff))) 224285612Sdelphij { 22554359Sroberto hlen = i + sizeof(*ip); 226330567Sgordon ip->ip_hl = (sizeof(*ip) + i) >> 2; 227330567Sgordon bcopy(optcpy, (char *)(ip + 1), i); 228330567Sgordon } 229330567Sgordon } 230285612Sdelphij } 231285612Sdelphij 232285612Sdelphij bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 233285612Sdelphij return err; 234285612Sdelphij} 235285612Sdelphij 236285612Sdelphij 237285612Sdelphij/* 238285612Sdelphij * send a tcp packet. 239285612Sdelphij */ 240285612Sdelphijint send_tcp(nfd, mtu, ip, gwip) 241285612Sdelphijint nfd, mtu; 242285612Sdelphijip_t *ip; 243293650Sglebiusstruct in_addr gwip; 244285612Sdelphij{ 245285612Sdelphij static tcp_seq iss = 2; 246285612Sdelphij struct tcpiphdr *ti; 247285612Sdelphij tcphdr_t *t; 248285612Sdelphij int thlen, i, iplen, hlen; 249316722Sdelphij u_32_t lbuf[20]; 250285612Sdelphij 251285612Sdelphij iplen = ip->ip_len; 252285612Sdelphij hlen = ip->ip_hl << 2; 253285612Sdelphij t = (tcphdr_t *)((char *)ip + hlen); 254285612Sdelphij ti = (struct tcpiphdr *)lbuf; 25554359Sroberto thlen = t->th_off << 2; 256289997Sglebius if (!thlen) 257285612Sdelphij thlen = sizeof(tcphdr_t); 258285612Sdelphij bzero((char *)ti, sizeof(*ti)); 259285612Sdelphij ip->ip_p = IPPROTO_TCP; 26054359Sroberto ti->ti_pr = ip->ip_p; 26154359Sroberto ti->ti_src = ip->ip_src; 262285612Sdelphij ti->ti_dst = ip->ip_dst; 263285612Sdelphij bcopy((char *)ip + hlen, (char *)&ti->ti_sport, thlen); 264285612Sdelphij 265285612Sdelphij if (!ti->ti_win) 266285612Sdelphij ti->ti_win = htons(4096); 267285612Sdelphij iss += 63; 268285612Sdelphij 269293650Sglebius i = sizeof(struct tcpiphdr) / sizeof(long); 27054359Sroberto 271285612Sdelphij if ((ti->ti_flags == TH_SYN) && !ntohs(ip->ip_off) && 272285612Sdelphij (lbuf[i] != htonl(0x020405b4))) { 273285612Sdelphij lbuf[i] = htonl(0x020405b4); 274285612Sdelphij bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, 275316722Sdelphij iplen - thlen - hlen); 276285612Sdelphij thlen += 4; 277285612Sdelphij } 278285612Sdelphij ti->ti_off = thlen >> 2; 279285612Sdelphij ti->ti_len = htons(thlen); 280285612Sdelphij ip->ip_len = hlen + thlen; 281285612Sdelphij ti->ti_sum = 0; 282289997Sglebius ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 283285612Sdelphij 284285612Sdelphij bcopy((char *)&ti->ti_sport, (char *)ip + hlen, thlen); 28554359Sroberto return send_ip(nfd, mtu, ip, gwip, 1); 28654359Sroberto} 28754359Sroberto 288285612Sdelphij 289285612Sdelphij/* 290285612Sdelphij * send a udp packet. 291285612Sdelphij */ 292285612Sdelphijint send_udp(nfd, mtu, ip, gwip) 293285612Sdelphijint nfd, mtu; 294285612Sdelphijip_t *ip; 295285612Sdelphijstruct in_addr gwip; 296285612Sdelphij{ 297285612Sdelphij struct tcpiphdr *ti; 298330567Sgordon int thlen; 299285612Sdelphij u_long lbuf[20]; 300285612Sdelphij 301285612Sdelphij ti = (struct tcpiphdr *)lbuf; 302285612Sdelphij bzero((char *)ti, sizeof(*ti)); 303285612Sdelphij thlen = sizeof(udphdr_t); 304285612Sdelphij ti->ti_pr = ip->ip_p; 305285612Sdelphij ti->ti_src = ip->ip_src; 306289997Sglebius ti->ti_dst = ip->ip_dst; 307285612Sdelphij bcopy((char *)ip + (ip->ip_hl << 2), 308285612Sdelphij (char *)&ti->ti_sport, sizeof(udphdr_t)); 309285612Sdelphij 310285612Sdelphij ti->ti_len = htons(thlen); 311285612Sdelphij ip->ip_len = (ip->ip_hl << 2) + thlen; 312285612Sdelphij ti->ti_sum = 0; 313285612Sdelphij ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 314285612Sdelphij 315285612Sdelphij bcopy((char *)&ti->ti_sport, 316285612Sdelphij (char *)ip + (ip->ip_hl << 2), sizeof(udphdr_t)); 317285612Sdelphij return send_ip(nfd, mtu, ip, gwip, 1); 318285612Sdelphij} 319285612Sdelphij 320285612Sdelphij 321285612Sdelphij/* 322285612Sdelphij * send an icmp packet. 323285612Sdelphij */ 324285612Sdelphijint send_icmp(nfd, mtu, ip, gwip) 325285612Sdelphijint nfd, mtu; 326285612Sdelphijip_t *ip; 327285612Sdelphijstruct in_addr gwip; 328285612Sdelphij{ 329285612Sdelphij struct icmp *ic; 330285612Sdelphij 331285612Sdelphij ic = (struct icmp *)((char *)ip + (ip->ip_hl << 2)); 332285612Sdelphij 333285612Sdelphij ic->icmp_cksum = 0; 334285612Sdelphij ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 335285612Sdelphij 336285612Sdelphij return send_ip(nfd, mtu, ip, gwip, 1); 337285612Sdelphij} 338285612Sdelphij 339285612Sdelphij 340285612Sdelphijint send_packet(nfd, mtu, ip, gwip) 341285612Sdelphijint nfd, mtu; 342285612Sdelphijip_t *ip; 343285612Sdelphijstruct in_addr gwip; 344285612Sdelphij{ 345285612Sdelphij switch (ip->ip_p) 346285612Sdelphij { 347285612Sdelphij case IPPROTO_TCP : 348330567Sgordon return send_tcp(nfd, mtu, ip, gwip); 349330567Sgordon case IPPROTO_UDP : 350285612Sdelphij return send_udp(nfd, mtu, ip, gwip); 351330567Sgordon case IPPROTO_ICMP : 352330567Sgordon return send_icmp(nfd, mtu, ip, gwip); 353330567Sgordon default : 354330567Sgordon return send_ip(nfd, mtu, ip, gwip, 1); 355330567Sgordon } 356330567Sgordon} 357330567Sgordon