1145519Sdarrenr/* $FreeBSD: stable/11/contrib/ipfilter/ipsend/ip.c 344833 2019-03-06 02:37:25Z cy $ */ 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"; 10255332Scystatic const char rcsid[] = "@(#)$Id$"; 1192686Sdarrenr#endif 12145510Sdarrenr#include <sys/param.h> 1322514Sdarrenr#include <sys/types.h> 1422514Sdarrenr#include <netinet/in_systm.h> 1522514Sdarrenr#include <sys/socket.h> 1622514Sdarrenr#include <net/if.h> 1722514Sdarrenr#include <netinet/in.h> 1822514Sdarrenr#include <netinet/ip.h> 1931183Speter#include <sys/param.h> 20255332Scy# include <net/route.h> 2131183Speter# include <netinet/if_ether.h> 2231183Speter# include <netinet/ip_var.h> 23145510Sdarrenr#include <errno.h> 24145510Sdarrenr#include <stdio.h> 25145510Sdarrenr#include <stdlib.h> 26145510Sdarrenr#include <unistd.h> 27145510Sdarrenr#include <string.h> 2824583Sdarrenr#include "ipsend.h" 2922514Sdarrenr 3022514Sdarrenr 3122514Sdarrenrstatic char *ipbuf = NULL, *ethbuf = NULL; 3222514Sdarrenr 3322514Sdarrenr 3422514Sdarrenru_short chksum(buf,len) 35255332Scy u_short *buf; 36255332Scy int len; 3722514Sdarrenr{ 3822514Sdarrenr u_long sum = 0; 3922514Sdarrenr int nwords = len >> 1; 4022514Sdarrenr 4122514Sdarrenr for(; nwords > 0; nwords--) 4222514Sdarrenr sum += *buf++; 4322514Sdarrenr sum = (sum>>16) + (sum & 0xffff); 4422514Sdarrenr sum += (sum >>16); 4522514Sdarrenr return (~sum); 4622514Sdarrenr} 4722514Sdarrenr 4822514Sdarrenr 4922514Sdarrenrint send_ether(nfd, buf, len, gwip) 50255332Scy int nfd, len; 51255332Scy char *buf; 52255332Scy struct in_addr gwip; 5322514Sdarrenr{ 5422514Sdarrenr static struct in_addr last_gw; 5522514Sdarrenr static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 5622514Sdarrenr ether_header_t *eh; 5722514Sdarrenr char *s; 5822514Sdarrenr int err; 5922514Sdarrenr 6022514Sdarrenr if (!ethbuf) 6122514Sdarrenr ethbuf = (char *)calloc(1, 65536+1024); 6222514Sdarrenr s = ethbuf; 6322514Sdarrenr eh = (ether_header_t *)s; 6422514Sdarrenr 6522514Sdarrenr bcopy((char *)buf, s + sizeof(*eh), len); 6622514Sdarrenr if (gwip.s_addr == last_gw.s_addr) 67145510Sdarrenr { 68342023Scy bcopy(last_arp, (char *) &eh->ether_dhost, 6); 69145510Sdarrenr } 70342023Scy else if (arp((char *)&gwip, (char *) &eh->ether_dhost) == -1) 7122514Sdarrenr { 7222514Sdarrenr perror("arp"); 7322514Sdarrenr return -2; 7422514Sdarrenr } 7531183Speter eh->ether_type = htons(ETHERTYPE_IP); 7622514Sdarrenr last_gw.s_addr = gwip.s_addr; 7722514Sdarrenr err = sendip(nfd, s, sizeof(*eh) + len); 7822514Sdarrenr return err; 7922514Sdarrenr} 8022514Sdarrenr 8122514Sdarrenr 8222514Sdarrenr/* 8322514Sdarrenr */ 8422514Sdarrenrint send_ip(nfd, mtu, ip, gwip, frag) 85255332Scy int nfd, mtu; 86255332Scy ip_t *ip; 87255332Scy struct in_addr gwip; 88255332Scy int frag; 8922514Sdarrenr{ 90145510Sdarrenr static struct in_addr last_gw, local_ip; 91145510Sdarrenr static char local_arp[6] = { 0, 0, 0, 0, 0, 0}; 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; 9634739Speter int err, iplen; 9722514Sdarrenr 9822514Sdarrenr if (!ipbuf) 9972003Sdarrenr { 10022514Sdarrenr ipbuf = (char *)malloc(65536); 101145510Sdarrenr if (!ipbuf) 10272003Sdarrenr { 10372003Sdarrenr perror("malloc failed"); 10472003Sdarrenr return -2; 10572003Sdarrenr } 10672003Sdarrenr } 10772003Sdarrenr 10822514Sdarrenr eh = (ether_header_t *)ipbuf; 10922514Sdarrenr 110342023Scy bzero((char *) &eh->ether_shost, sizeof(eh->ether_shost)); 11122514Sdarrenr if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 112145510Sdarrenr { 113342023Scy bcopy(last_arp, (char *) &eh->ether_dhost, 6); 114145510Sdarrenr } 115342023Scy else if (arp((char *)&gwip, (char *) &eh->ether_dhost) == -1) 11622514Sdarrenr { 11722514Sdarrenr perror("arp"); 11822514Sdarrenr return -2; 11922514Sdarrenr } 120342023Scy bcopy((char *) &eh->ether_dhost, last_arp, sizeof(last_arp)); 12131183Speter eh->ether_type = htons(ETHERTYPE_IP); 12222514Sdarrenr 12322514Sdarrenr bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 12422514Sdarrenr last_gw.s_addr = gwip.s_addr; 12534739Speter iplen = ip->ip_len; 12634739Speter ip->ip_len = htons(iplen); 12731183Speter if (!(frag & 2)) { 128145510Sdarrenr if (!IP_V(ip)) 129145510Sdarrenr IP_V_A(ip, IPVERSION); 13031183Speter if (!ip->ip_id) 13131183Speter ip->ip_id = htons(id++); 13231183Speter if (!ip->ip_ttl) 13331183Speter ip->ip_ttl = 60; 13431183Speter } 13522514Sdarrenr 136145510Sdarrenr if (ip->ip_src.s_addr != local_ip.s_addr) { 137342023Scy (void) arp((char *)&ip->ip_src, (char *) &local_arp); 138342023Scy bcopy(local_arp, (char *) &eh->ether_shost,sizeof(last_arp)); 139145510Sdarrenr local_ip = ip->ip_src; 140145510Sdarrenr } else 141342023Scy bcopy(local_arp, (char *) &eh->ether_shost, 6); 142145510Sdarrenr 14334739Speter if (!frag || (sizeof(*eh) + iplen < mtu)) 14422514Sdarrenr { 14522514Sdarrenr ip->ip_sum = 0; 146145510Sdarrenr ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); 14722514Sdarrenr 14834739Speter bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); 14934739Speter err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); 15022514Sdarrenr } 15122514Sdarrenr else 15222514Sdarrenr { 15322514Sdarrenr /* 15422514Sdarrenr * Actually, this is bogus because we're putting all IP 15522514Sdarrenr * options in every packet, which isn't always what should be 15622514Sdarrenr * done. Will do for now. 15722514Sdarrenr */ 15822514Sdarrenr ether_header_t eth; 15922514Sdarrenr char optcpy[48], ol; 16022514Sdarrenr char *s; 16134739Speter int i, sent = 0, ts, hlen, olen; 16222514Sdarrenr 163145510Sdarrenr hlen = IP_HL(ip) << 2; 16422514Sdarrenr if (mtu < (hlen + 8)) { 16522514Sdarrenr fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 16622514Sdarrenr mtu, hlen); 16722514Sdarrenr fprintf(stderr, "can't fragment data\n"); 16822514Sdarrenr return -2; 16922514Sdarrenr } 170145510Sdarrenr ol = (IP_HL(ip) << 2) - sizeof(*ip); 17122514Sdarrenr for (i = 0, s = (char*)(ip + 1); ol > 0; ) 17222514Sdarrenr if (*s == IPOPT_EOL) { 17322514Sdarrenr optcpy[i++] = *s; 17422514Sdarrenr break; 17522514Sdarrenr } else if (*s == IPOPT_NOP) { 17622514Sdarrenr s++; 17722514Sdarrenr ol--; 17822514Sdarrenr } else 17922514Sdarrenr { 18022514Sdarrenr olen = (int)(*(u_char *)(s + 1)); 18122514Sdarrenr ol -= olen; 18222514Sdarrenr if (IPOPT_COPIED(*s)) 18322514Sdarrenr { 18422514Sdarrenr bcopy(s, optcpy + i, olen); 18522514Sdarrenr i += olen; 18622514Sdarrenr s += olen; 18722514Sdarrenr } 18822514Sdarrenr } 18922514Sdarrenr if (i) 19022514Sdarrenr { 19122514Sdarrenr /* 19222514Sdarrenr * pad out 19322514Sdarrenr */ 19422514Sdarrenr while ((i & 3) && (i & 3) != 3) 19522514Sdarrenr optcpy[i++] = IPOPT_NOP; 19622514Sdarrenr if ((i & 3) == 3) 19722514Sdarrenr optcpy[i++] = IPOPT_EOL; 19822514Sdarrenr } 19922514Sdarrenr 20022514Sdarrenr bcopy((char *)eh, (char *)ð, sizeof(eth)); 20122514Sdarrenr s = (char *)ip + hlen; 20222514Sdarrenr iplen = ntohs(ip->ip_len) - hlen; 20322514Sdarrenr ip->ip_off |= htons(IP_MF); 20422514Sdarrenr 20522514Sdarrenr while (1) 20622514Sdarrenr { 20722514Sdarrenr if ((sent + (mtu - hlen)) >= iplen) 20822514Sdarrenr { 20922514Sdarrenr ip->ip_off ^= htons(IP_MF); 21022514Sdarrenr ts = iplen - sent; 21122514Sdarrenr } 21222514Sdarrenr else 21322514Sdarrenr ts = (mtu - hlen); 21422514Sdarrenr ip->ip_off &= htons(0xe000); 21522514Sdarrenr ip->ip_off |= htons(sent >> 3); 21622514Sdarrenr ts += hlen; 21722514Sdarrenr ip->ip_len = htons(ts); 21822514Sdarrenr ip->ip_sum = 0; 21924583Sdarrenr ip->ip_sum = chksum((u_short *)ip, hlen); 22022514Sdarrenr bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 22122514Sdarrenr bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 22222514Sdarrenr err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 22322514Sdarrenr 22422514Sdarrenr bcopy((char *)ð, ipbuf, sizeof(eth)); 22522514Sdarrenr sent += (ts - hlen); 22622514Sdarrenr if (!(ntohs(ip->ip_off) & IP_MF)) 22722514Sdarrenr break; 22822514Sdarrenr else if (!(ip->ip_off & htons(0x1fff))) 22922514Sdarrenr { 23022514Sdarrenr hlen = i + sizeof(*ip); 231145510Sdarrenr IP_HL_A(ip, (sizeof(*ip) + i) >> 2); 23222514Sdarrenr bcopy(optcpy, (char *)(ip + 1), i); 23322514Sdarrenr } 23422514Sdarrenr } 23522514Sdarrenr } 23622514Sdarrenr 23722514Sdarrenr bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 23822514Sdarrenr return err; 23922514Sdarrenr} 24022514Sdarrenr 24122514Sdarrenr 24222514Sdarrenr/* 24322514Sdarrenr * send a tcp packet. 24422514Sdarrenr */ 24522514Sdarrenrint send_tcp(nfd, mtu, ip, gwip) 246255332Scy int nfd, mtu; 247255332Scy ip_t *ip; 248255332Scy struct in_addr gwip; 24922514Sdarrenr{ 25022514Sdarrenr static tcp_seq iss = 2; 251145510Sdarrenr tcphdr_t *t, *t2; 25234739Speter int thlen, i, iplen, hlen; 25334739Speter u_32_t lbuf[20]; 254145510Sdarrenr ip_t *ip2; 25522514Sdarrenr 25634739Speter iplen = ip->ip_len; 257145510Sdarrenr hlen = IP_HL(ip) << 2; 25834739Speter t = (tcphdr_t *)((char *)ip + hlen); 259145510Sdarrenr ip2 = (struct ip *)lbuf; 260145510Sdarrenr t2 = (tcphdr_t *)((char *)ip2 + hlen); 261145510Sdarrenr thlen = TCP_OFF(t) << 2; 26234739Speter if (!thlen) 26334739Speter thlen = sizeof(tcphdr_t); 264145510Sdarrenr bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2)); 26522514Sdarrenr ip->ip_p = IPPROTO_TCP; 266145510Sdarrenr ip2->ip_p = ip->ip_p; 267145510Sdarrenr ip2->ip_src = ip->ip_src; 268145510Sdarrenr ip2->ip_dst = ip->ip_dst; 269145510Sdarrenr bcopy((char *)ip + hlen, (char *)t2, thlen); 27022514Sdarrenr 271145510Sdarrenr if (!t2->th_win) 272145510Sdarrenr t2->th_win = htons(4096); 27334739Speter iss += 63; 27422514Sdarrenr 27534739Speter i = sizeof(struct tcpiphdr) / sizeof(long); 27634739Speter 277145510Sdarrenr if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) && 27834739Speter (lbuf[i] != htonl(0x020405b4))) { 27922514Sdarrenr lbuf[i] = htonl(0x020405b4); 28034739Speter bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, 28134739Speter iplen - thlen - hlen); 28222514Sdarrenr thlen += 4; 28322514Sdarrenr } 284145510Sdarrenr TCP_OFF_A(t2, thlen >> 2); 285145510Sdarrenr ip2->ip_len = htons(thlen); 28634739Speter ip->ip_len = hlen + thlen; 287145510Sdarrenr t2->th_sum = 0; 288145510Sdarrenr t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t)); 28922514Sdarrenr 290145510Sdarrenr bcopy((char *)t2, (char *)ip + hlen, thlen); 29122514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 29222514Sdarrenr} 29322514Sdarrenr 29422514Sdarrenr 29522514Sdarrenr/* 29622514Sdarrenr * send a udp packet. 29722514Sdarrenr */ 29822514Sdarrenrint send_udp(nfd, mtu, ip, gwip) 299255332Scy int nfd, mtu; 300255332Scy ip_t *ip; 301255332Scy struct in_addr gwip; 30222514Sdarrenr{ 30322514Sdarrenr struct tcpiphdr *ti; 30422514Sdarrenr int thlen; 30522514Sdarrenr u_long lbuf[20]; 30622514Sdarrenr 30722514Sdarrenr ti = (struct tcpiphdr *)lbuf; 30822514Sdarrenr bzero((char *)ti, sizeof(*ti)); 30922514Sdarrenr thlen = sizeof(udphdr_t); 31022514Sdarrenr ti->ti_pr = ip->ip_p; 31122514Sdarrenr ti->ti_src = ip->ip_src; 31222514Sdarrenr ti->ti_dst = ip->ip_dst; 313145510Sdarrenr bcopy((char *)ip + (IP_HL(ip) << 2), 31422514Sdarrenr (char *)&ti->ti_sport, sizeof(udphdr_t)); 31522514Sdarrenr 31622514Sdarrenr ti->ti_len = htons(thlen); 317145510Sdarrenr ip->ip_len = (IP_HL(ip) << 2) + thlen; 31822514Sdarrenr ti->ti_sum = 0; 31924583Sdarrenr ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 32022514Sdarrenr 32122514Sdarrenr bcopy((char *)&ti->ti_sport, 322145510Sdarrenr (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t)); 32322514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 32422514Sdarrenr} 32522514Sdarrenr 32622514Sdarrenr 32722514Sdarrenr/* 32822514Sdarrenr * send an icmp packet. 32922514Sdarrenr */ 33022514Sdarrenrint send_icmp(nfd, mtu, ip, gwip) 331255332Scy int nfd, mtu; 332255332Scy ip_t *ip; 333255332Scy struct in_addr gwip; 33422514Sdarrenr{ 33522514Sdarrenr struct icmp *ic; 33622514Sdarrenr 337145510Sdarrenr ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); 33822514Sdarrenr 33922514Sdarrenr ic->icmp_cksum = 0; 34024583Sdarrenr ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 34122514Sdarrenr 34222514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 34322514Sdarrenr} 34422514Sdarrenr 34522514Sdarrenr 34622514Sdarrenrint send_packet(nfd, mtu, ip, gwip) 347255332Scy int nfd, mtu; 348255332Scy ip_t *ip; 349255332Scy struct in_addr gwip; 35022514Sdarrenr{ 35122514Sdarrenr switch (ip->ip_p) 35222514Sdarrenr { 35322514Sdarrenr case IPPROTO_TCP : 35422514Sdarrenr return send_tcp(nfd, mtu, ip, gwip); 35522514Sdarrenr case IPPROTO_UDP : 35622514Sdarrenr return send_udp(nfd, mtu, ip, gwip); 35722514Sdarrenr case IPPROTO_ICMP : 35822514Sdarrenr return send_icmp(nfd, mtu, ip, gwip); 35922514Sdarrenr default : 36022514Sdarrenr return send_ip(nfd, mtu, ip, gwip, 1); 36122514Sdarrenr } 36222514Sdarrenr} 363