1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 322514Sdarrenr/* 453024Sguido * ip.c (C) 1995-1998 Darren Reed 522514Sdarrenr * 680486Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 722514Sdarrenr */ 8145510Sdarrenr#if !defined(lint) 9145510Sdarrenrstatic const char sccsid[] = "%W% %G% (C)1995"; 10170268Sdarrenrstatic const char rcsid[] = "@(#)$Id: ip.c,v 2.8.2.2 2007/02/17 12:41:51 darrenr Exp $"; 1192686Sdarrenr#endif 12145510Sdarrenr#include <sys/param.h> 1322514Sdarrenr#include <sys/types.h> 1422514Sdarrenr#include <netinet/in_systm.h> 1522514Sdarrenr#include <sys/socket.h> 16170268Sdarrenr#ifdef __osf__ 17170268Sdarrenr# include "radix_ipf_local.h" 18170268Sdarrenr#endif 1922514Sdarrenr#include <net/if.h> 2022514Sdarrenr#include <netinet/in.h> 2122514Sdarrenr#include <netinet/ip.h> 2231183Speter#include <sys/param.h> 2322514Sdarrenr#ifndef linux 2431183Speter# include <netinet/if_ether.h> 2531183Speter# include <netinet/ip_var.h> 2631183Speter# if __FreeBSD_version >= 300000 2731183Speter# include <net/if_var.h> 2831183Speter# endif 2922514Sdarrenr#endif 30145510Sdarrenr#include <errno.h> 31145510Sdarrenr#include <stdio.h> 32145510Sdarrenr#include <stdlib.h> 33145510Sdarrenr#include <unistd.h> 34145510Sdarrenr#include <string.h> 3524583Sdarrenr#include "ipsend.h" 3622514Sdarrenr 3722514Sdarrenr 3822514Sdarrenrstatic char *ipbuf = NULL, *ethbuf = NULL; 3922514Sdarrenr 4022514Sdarrenr 4122514Sdarrenru_short chksum(buf,len) 4222514Sdarrenru_short *buf; 4322514Sdarrenrint len; 4422514Sdarrenr{ 4522514Sdarrenr u_long sum = 0; 4622514Sdarrenr int nwords = len >> 1; 4722514Sdarrenr 4822514Sdarrenr for(; nwords > 0; nwords--) 4922514Sdarrenr sum += *buf++; 5022514Sdarrenr sum = (sum>>16) + (sum & 0xffff); 5122514Sdarrenr sum += (sum >>16); 5222514Sdarrenr return (~sum); 5322514Sdarrenr} 5422514Sdarrenr 5522514Sdarrenr 5622514Sdarrenrint send_ether(nfd, buf, len, gwip) 5722514Sdarrenrint nfd, len; 5822514Sdarrenrchar *buf; 5922514Sdarrenrstruct in_addr gwip; 6022514Sdarrenr{ 6122514Sdarrenr static struct in_addr last_gw; 6222514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 6322514Sdarrenr ether_header_t *eh; 6422514Sdarrenr char *s; 6522514Sdarrenr int err; 6622514Sdarrenr 6722514Sdarrenr if (!ethbuf) 6822514Sdarrenr ethbuf = (char *)calloc(1, 65536+1024); 6922514Sdarrenr s = ethbuf; 7022514Sdarrenr eh = (ether_header_t *)s; 7122514Sdarrenr 7222514Sdarrenr bcopy((char *)buf, s + sizeof(*eh), len); 7322514Sdarrenr if (gwip.s_addr == last_gw.s_addr) 74145510Sdarrenr { 7531183Speter bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 76145510Sdarrenr } 7731183Speter else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 7822514Sdarrenr { 7922514Sdarrenr perror("arp"); 8022514Sdarrenr return -2; 8122514Sdarrenr } 8231183Speter eh->ether_type = htons(ETHERTYPE_IP); 8322514Sdarrenr last_gw.s_addr = gwip.s_addr; 8422514Sdarrenr err = sendip(nfd, s, sizeof(*eh) + len); 8522514Sdarrenr return err; 8622514Sdarrenr} 8722514Sdarrenr 8822514Sdarrenr 8922514Sdarrenr/* 9022514Sdarrenr */ 9122514Sdarrenrint send_ip(nfd, mtu, ip, gwip, frag) 9222514Sdarrenrint nfd, mtu; 9322514Sdarrenrip_t *ip; 9422514Sdarrenrstruct in_addr gwip; 9522514Sdarrenrint frag; 9622514Sdarrenr{ 97145510Sdarrenr static struct in_addr last_gw, local_ip; 98145510Sdarrenr static char local_arp[6] = { 0, 0, 0, 0, 0, 0}; 9922514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 10022514Sdarrenr static u_short id = 0; 10122514Sdarrenr ether_header_t *eh; 10222514Sdarrenr ip_t ipsv; 10334739Speter int err, iplen; 10422514Sdarrenr 10522514Sdarrenr if (!ipbuf) 10672003Sdarrenr { 10722514Sdarrenr ipbuf = (char *)malloc(65536); 108145510Sdarrenr if (!ipbuf) 10972003Sdarrenr { 11072003Sdarrenr perror("malloc failed"); 11172003Sdarrenr return -2; 11272003Sdarrenr } 11372003Sdarrenr } 11472003Sdarrenr 11522514Sdarrenr eh = (ether_header_t *)ipbuf; 11622514Sdarrenr 11731183Speter bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost)); 11822514Sdarrenr if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 119145510Sdarrenr { 12031183Speter bcopy(last_arp, (char *)A_A eh->ether_dhost, 6); 121145510Sdarrenr } 12231183Speter else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1) 12322514Sdarrenr { 12422514Sdarrenr perror("arp"); 12522514Sdarrenr return -2; 12622514Sdarrenr } 12731183Speter bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp)); 12831183Speter eh->ether_type = htons(ETHERTYPE_IP); 12922514Sdarrenr 13022514Sdarrenr bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 13122514Sdarrenr last_gw.s_addr = gwip.s_addr; 13234739Speter iplen = ip->ip_len; 13334739Speter ip->ip_len = htons(iplen); 13431183Speter if (!(frag & 2)) { 135145510Sdarrenr if (!IP_V(ip)) 136145510Sdarrenr IP_V_A(ip, IPVERSION); 13731183Speter if (!ip->ip_id) 13831183Speter ip->ip_id = htons(id++); 13931183Speter if (!ip->ip_ttl) 14031183Speter ip->ip_ttl = 60; 14131183Speter } 14222514Sdarrenr 143145510Sdarrenr if (ip->ip_src.s_addr != local_ip.s_addr) { 144145510Sdarrenr (void) arp((char *)&ip->ip_src, (char *)A_A local_arp); 145145510Sdarrenr bcopy(local_arp, (char *)A_A eh->ether_shost,sizeof(last_arp)); 146145510Sdarrenr local_ip = ip->ip_src; 147145510Sdarrenr } else 148145510Sdarrenr bcopy(local_arp, (char *)A_A eh->ether_shost, 6); 149145510Sdarrenr 15034739Speter if (!frag || (sizeof(*eh) + iplen < mtu)) 15122514Sdarrenr { 15222514Sdarrenr ip->ip_sum = 0; 153145510Sdarrenr ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); 15422514Sdarrenr 15534739Speter bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); 15634739Speter err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); 15722514Sdarrenr } 15822514Sdarrenr else 15922514Sdarrenr { 16022514Sdarrenr /* 16122514Sdarrenr * Actually, this is bogus because we're putting all IP 16222514Sdarrenr * options in every packet, which isn't always what should be 16322514Sdarrenr * done. Will do for now. 16422514Sdarrenr */ 16522514Sdarrenr ether_header_t eth; 16622514Sdarrenr char optcpy[48], ol; 16722514Sdarrenr char *s; 16834739Speter int i, sent = 0, ts, hlen, olen; 16922514Sdarrenr 170145510Sdarrenr hlen = IP_HL(ip) << 2; 17122514Sdarrenr if (mtu < (hlen + 8)) { 17222514Sdarrenr fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 17322514Sdarrenr mtu, hlen); 17422514Sdarrenr fprintf(stderr, "can't fragment data\n"); 17522514Sdarrenr return -2; 17622514Sdarrenr } 177145510Sdarrenr ol = (IP_HL(ip) << 2) - sizeof(*ip); 17822514Sdarrenr for (i = 0, s = (char*)(ip + 1); ol > 0; ) 17922514Sdarrenr if (*s == IPOPT_EOL) { 18022514Sdarrenr optcpy[i++] = *s; 18122514Sdarrenr break; 18222514Sdarrenr } else if (*s == IPOPT_NOP) { 18322514Sdarrenr s++; 18422514Sdarrenr ol--; 18522514Sdarrenr } else 18622514Sdarrenr { 18722514Sdarrenr olen = (int)(*(u_char *)(s + 1)); 18822514Sdarrenr ol -= olen; 18922514Sdarrenr if (IPOPT_COPIED(*s)) 19022514Sdarrenr { 19122514Sdarrenr bcopy(s, optcpy + i, olen); 19222514Sdarrenr i += olen; 19322514Sdarrenr s += olen; 19422514Sdarrenr } 19522514Sdarrenr } 19622514Sdarrenr if (i) 19722514Sdarrenr { 19822514Sdarrenr /* 19922514Sdarrenr * pad out 20022514Sdarrenr */ 20122514Sdarrenr while ((i & 3) && (i & 3) != 3) 20222514Sdarrenr optcpy[i++] = IPOPT_NOP; 20322514Sdarrenr if ((i & 3) == 3) 20422514Sdarrenr optcpy[i++] = IPOPT_EOL; 20522514Sdarrenr } 20622514Sdarrenr 20722514Sdarrenr bcopy((char *)eh, (char *)ð, sizeof(eth)); 20822514Sdarrenr s = (char *)ip + hlen; 20922514Sdarrenr iplen = ntohs(ip->ip_len) - hlen; 21022514Sdarrenr ip->ip_off |= htons(IP_MF); 21122514Sdarrenr 21222514Sdarrenr while (1) 21322514Sdarrenr { 21422514Sdarrenr if ((sent + (mtu - hlen)) >= iplen) 21522514Sdarrenr { 21622514Sdarrenr ip->ip_off ^= htons(IP_MF); 21722514Sdarrenr ts = iplen - sent; 21822514Sdarrenr } 21922514Sdarrenr else 22022514Sdarrenr ts = (mtu - hlen); 22122514Sdarrenr ip->ip_off &= htons(0xe000); 22222514Sdarrenr ip->ip_off |= htons(sent >> 3); 22322514Sdarrenr ts += hlen; 22422514Sdarrenr ip->ip_len = htons(ts); 22522514Sdarrenr ip->ip_sum = 0; 22624583Sdarrenr ip->ip_sum = chksum((u_short *)ip, hlen); 22722514Sdarrenr bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 22822514Sdarrenr bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 22922514Sdarrenr err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 23022514Sdarrenr 23122514Sdarrenr bcopy((char *)ð, ipbuf, sizeof(eth)); 23222514Sdarrenr sent += (ts - hlen); 23322514Sdarrenr if (!(ntohs(ip->ip_off) & IP_MF)) 23422514Sdarrenr break; 23522514Sdarrenr else if (!(ip->ip_off & htons(0x1fff))) 23622514Sdarrenr { 23722514Sdarrenr hlen = i + sizeof(*ip); 238145510Sdarrenr IP_HL_A(ip, (sizeof(*ip) + i) >> 2); 23922514Sdarrenr bcopy(optcpy, (char *)(ip + 1), i); 24022514Sdarrenr } 24122514Sdarrenr } 24222514Sdarrenr } 24322514Sdarrenr 24422514Sdarrenr bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 24522514Sdarrenr return err; 24622514Sdarrenr} 24722514Sdarrenr 24822514Sdarrenr 24922514Sdarrenr/* 25022514Sdarrenr * send a tcp packet. 25122514Sdarrenr */ 25222514Sdarrenrint send_tcp(nfd, mtu, ip, gwip) 25322514Sdarrenrint nfd, mtu; 25422514Sdarrenrip_t *ip; 25522514Sdarrenrstruct in_addr gwip; 25622514Sdarrenr{ 25722514Sdarrenr static tcp_seq iss = 2; 258145510Sdarrenr tcphdr_t *t, *t2; 25934739Speter int thlen, i, iplen, hlen; 26034739Speter u_32_t lbuf[20]; 261145510Sdarrenr ip_t *ip2; 26222514Sdarrenr 26334739Speter iplen = ip->ip_len; 264145510Sdarrenr hlen = IP_HL(ip) << 2; 26534739Speter t = (tcphdr_t *)((char *)ip + hlen); 266145510Sdarrenr ip2 = (struct ip *)lbuf; 267145510Sdarrenr t2 = (tcphdr_t *)((char *)ip2 + hlen); 268145510Sdarrenr thlen = TCP_OFF(t) << 2; 26934739Speter if (!thlen) 27034739Speter thlen = sizeof(tcphdr_t); 271145510Sdarrenr bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2)); 27222514Sdarrenr ip->ip_p = IPPROTO_TCP; 273145510Sdarrenr ip2->ip_p = ip->ip_p; 274145510Sdarrenr ip2->ip_src = ip->ip_src; 275145510Sdarrenr ip2->ip_dst = ip->ip_dst; 276145510Sdarrenr bcopy((char *)ip + hlen, (char *)t2, thlen); 27722514Sdarrenr 278145510Sdarrenr if (!t2->th_win) 279145510Sdarrenr t2->th_win = htons(4096); 28034739Speter iss += 63; 28122514Sdarrenr 28234739Speter i = sizeof(struct tcpiphdr) / sizeof(long); 28334739Speter 284145510Sdarrenr if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) && 28534739Speter (lbuf[i] != htonl(0x020405b4))) { 28622514Sdarrenr lbuf[i] = htonl(0x020405b4); 28734739Speter bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, 28834739Speter iplen - thlen - hlen); 28922514Sdarrenr thlen += 4; 29022514Sdarrenr } 291145510Sdarrenr TCP_OFF_A(t2, thlen >> 2); 292145510Sdarrenr ip2->ip_len = htons(thlen); 29334739Speter ip->ip_len = hlen + thlen; 294145510Sdarrenr t2->th_sum = 0; 295145510Sdarrenr t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t)); 29622514Sdarrenr 297145510Sdarrenr bcopy((char *)t2, (char *)ip + hlen, thlen); 29822514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 29922514Sdarrenr} 30022514Sdarrenr 30122514Sdarrenr 30222514Sdarrenr/* 30322514Sdarrenr * send a udp packet. 30422514Sdarrenr */ 30522514Sdarrenrint send_udp(nfd, mtu, ip, gwip) 30622514Sdarrenrint nfd, mtu; 30722514Sdarrenrip_t *ip; 30822514Sdarrenrstruct in_addr gwip; 30922514Sdarrenr{ 31022514Sdarrenr struct tcpiphdr *ti; 31122514Sdarrenr int thlen; 31222514Sdarrenr u_long lbuf[20]; 31322514Sdarrenr 31422514Sdarrenr ti = (struct tcpiphdr *)lbuf; 31522514Sdarrenr bzero((char *)ti, sizeof(*ti)); 31622514Sdarrenr thlen = sizeof(udphdr_t); 31722514Sdarrenr ti->ti_pr = ip->ip_p; 31822514Sdarrenr ti->ti_src = ip->ip_src; 31922514Sdarrenr ti->ti_dst = ip->ip_dst; 320145510Sdarrenr bcopy((char *)ip + (IP_HL(ip) << 2), 32122514Sdarrenr (char *)&ti->ti_sport, sizeof(udphdr_t)); 32222514Sdarrenr 32322514Sdarrenr ti->ti_len = htons(thlen); 324145510Sdarrenr ip->ip_len = (IP_HL(ip) << 2) + thlen; 32522514Sdarrenr ti->ti_sum = 0; 32624583Sdarrenr ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 32722514Sdarrenr 32822514Sdarrenr bcopy((char *)&ti->ti_sport, 329145510Sdarrenr (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t)); 33022514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 33122514Sdarrenr} 33222514Sdarrenr 33322514Sdarrenr 33422514Sdarrenr/* 33522514Sdarrenr * send an icmp packet. 33622514Sdarrenr */ 33722514Sdarrenrint send_icmp(nfd, mtu, ip, gwip) 33822514Sdarrenrint nfd, mtu; 33922514Sdarrenrip_t *ip; 34022514Sdarrenrstruct in_addr gwip; 34122514Sdarrenr{ 34222514Sdarrenr struct icmp *ic; 34322514Sdarrenr 344145510Sdarrenr ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); 34522514Sdarrenr 34622514Sdarrenr ic->icmp_cksum = 0; 34724583Sdarrenr ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 34822514Sdarrenr 34922514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 35022514Sdarrenr} 35122514Sdarrenr 35222514Sdarrenr 35322514Sdarrenrint send_packet(nfd, mtu, ip, gwip) 35422514Sdarrenrint nfd, mtu; 35522514Sdarrenrip_t *ip; 35622514Sdarrenrstruct in_addr gwip; 35722514Sdarrenr{ 35822514Sdarrenr switch (ip->ip_p) 35922514Sdarrenr { 36022514Sdarrenr case IPPROTO_TCP : 36122514Sdarrenr return send_tcp(nfd, mtu, ip, gwip); 36222514Sdarrenr case IPPROTO_UDP : 36322514Sdarrenr return send_udp(nfd, mtu, ip, gwip); 36422514Sdarrenr case IPPROTO_ICMP : 36522514Sdarrenr return send_icmp(nfd, mtu, ip, gwip); 36622514Sdarrenr default : 36722514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 36822514Sdarrenr } 36922514Sdarrenr} 370