Home | History | Annotate | Line # | Download | only in ipsend
      1 /*	$NetBSD: ip.c,v 1.4 2018/02/04 08:19:42 mrg Exp $	*/
      2 
      3 /*
      4  * ip.c (C) 1995-1998 Darren Reed
      5  *
      6  * See the IPFILTER.LICENCE file for details on licencing.
      7  */
      8 #if !defined(lint)
      9 static __attribute__((__used__)) const char sccsid[] = "%W% %G% (C)1995";
     10 static __attribute__((__used__)) const char rcsid[] = "@(#)Id: ip.c,v 1.1.1.2 2012/07/22 13:44:36 darrenr";
     11 #endif
     12 #include <sys/param.h>
     13 #include <sys/types.h>
     14 #include <netinet/in_systm.h>
     15 #include <sys/socket.h>
     16 #include <net/if.h>
     17 #include <netinet/in.h>
     18 #include <netinet/ip.h>
     19 #include <sys/param.h>
     20 #ifndef	linux
     21 # include <net/route.h>
     22 # include <netinet/if_ether.h>
     23 # include <netinet/ip_var.h>
     24 # if __FreeBSD_version >= 300000
     25 #  include <net/if_var.h>
     26 # endif
     27 #endif
     28 #include <errno.h>
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <unistd.h>
     32 #include <string.h>
     33 #include "ipsend.h"
     34 
     35 
     36 static	char	*ipbuf = NULL, *ethbuf = NULL;
     37 
     38 
     39 u_short	chksum(buf,len)
     40 	u_short	*buf;
     41 	int	len;
     42 {
     43 	u_long	sum = 0;
     44 	int	nwords = len >> 1;
     45 
     46 	for(; nwords > 0; nwords--)
     47 		sum += *buf++;
     48 	sum = (sum>>16) + (sum & 0xffff);
     49 	sum += (sum >>16);
     50 	return (~sum);
     51 }
     52 
     53 
     54 int	send_ether(nfd, buf, len, gwip)
     55 	int	nfd, len;
     56 	char	*buf;
     57 	struct	in_addr	gwip;
     58 {
     59 	static	struct	in_addr	last_gw;
     60 	static	char	last_arp[6] = { 0, 0, 0, 0, 0, 0};
     61 	ether_header_t	*eh;
     62 	char	*s;
     63 	int	err;
     64 
     65 	if (!ethbuf)
     66 		ethbuf = (char *)calloc(1, 65536+1024);
     67 	s = ethbuf;
     68 	eh = (ether_header_t *)s;
     69 
     70 	bcopy((char *)buf, s + sizeof(*eh), len);
     71 	if (gwip.s_addr == last_gw.s_addr)
     72 	    {
     73 		bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
     74 	    }
     75 	else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
     76 	    {
     77 		perror("arp");
     78 		return -2;
     79 	    }
     80 	eh->ether_type = htons(ETHERTYPE_IP);
     81 	last_gw.s_addr = gwip.s_addr;
     82 	err = sendip(nfd, s, sizeof(*eh) + len);
     83 	return err;
     84 }
     85 
     86 
     87 /*
     88  */
     89 int	send_ip(nfd, mtu, ip, gwip, frag)
     90 	int	nfd, mtu;
     91 	ip_t	*ip;
     92 	struct	in_addr	gwip;
     93 	int	frag;
     94 {
     95 	static	struct	in_addr	last_gw, local_ip;
     96 	static	char	local_arp[6] = { 0, 0, 0, 0, 0, 0};
     97 	static	char	last_arp[6] = { 0, 0, 0, 0, 0, 0};
     98 	static	u_short	id = 0;
     99 	ether_header_t	*eh;
    100 	ip_t	ipsv;
    101 	int	err, iplen;
    102 
    103 	if (!ipbuf)
    104 	  {
    105 		ipbuf = (char *)malloc(65536);
    106 		if (!ipbuf)
    107 		  {
    108 			perror("malloc failed");
    109 			return -2;
    110 		  }
    111 	  }
    112 
    113 	eh = (ether_header_t *)ipbuf;
    114 
    115 	bzero((char *)A_A eh->ether_shost, sizeof(eh->ether_shost));
    116 	if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr))
    117 	    {
    118 		bcopy(last_arp, (char *)A_A eh->ether_dhost, 6);
    119 	    }
    120 	else if (arp((char *)&gwip, (char *)A_A eh->ether_dhost) == -1)
    121 	    {
    122 		perror("arp");
    123 		return -2;
    124 	    }
    125 	bcopy((char *)A_A eh->ether_dhost, last_arp, sizeof(last_arp));
    126 	eh->ether_type = htons(ETHERTYPE_IP);
    127 
    128 	bcopy((char *)ip, (char *)&ipsv, sizeof(*ip));
    129 	last_gw.s_addr = gwip.s_addr;
    130 	iplen = ip->ip_len;
    131 	ip->ip_len = htons(iplen);
    132 	if (!(frag & 2)) {
    133 		if (!IP_V(ip))
    134 			IP_V_A(ip, IPVERSION);
    135 		if (!ip->ip_id)
    136 			ip->ip_id  = htons(id++);
    137 		if (!ip->ip_ttl)
    138 			ip->ip_ttl = 60;
    139 	}
    140 
    141 	if (ip->ip_src.s_addr != local_ip.s_addr) {
    142 		(void) arp((char *)&ip->ip_src, (char *)A_A local_arp);
    143 		bcopy(local_arp, (char *)A_A eh->ether_shost,sizeof(last_arp));
    144 		local_ip = ip->ip_src;
    145 	} else
    146 		bcopy(local_arp, (char *)A_A eh->ether_shost, 6);
    147 
    148 	if (!frag || (sizeof(*eh) + iplen < mtu))
    149 	    {
    150 		ip->ip_sum = 0;
    151 		ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2);
    152 
    153 		bcopy((char *)ip, ipbuf + sizeof(*eh), iplen);
    154 		err =  sendip(nfd, ipbuf, sizeof(*eh) + iplen);
    155 	    }
    156 	else
    157 	    {
    158 		/*
    159 		 * Actually, this is bogus because we're putting all IP
    160 		 * options in every packet, which isn't always what should be
    161 		 * done.  Will do for now.
    162 		 */
    163 		ether_header_t	eth;
    164 		char	optcpy[48], ol;
    165 		char	*s;
    166 		int	i, sent = 0, ts, hlen, olen;
    167 
    168 		hlen = IP_HL(ip) << 2;
    169 		if (mtu < (hlen + 8)) {
    170 			fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n",
    171 				mtu, hlen);
    172 			fprintf(stderr, "can't fragment data\n");
    173 			return -2;
    174 		}
    175 		ol = (IP_HL(ip) << 2) - sizeof(*ip);
    176 		for (i = 0, s = (char*)(ip + 1); ol > 0; )
    177 			if (*s == IPOPT_EOL) {
    178 				optcpy[i++] = *s;
    179 				break;
    180 			} else if (*s == IPOPT_NOP) {
    181 				s++;
    182 				ol--;
    183 			} else
    184 			    {
    185 				olen = (int)(*(u_char *)(s + 1));
    186 				ol -= olen;
    187 				if (IPOPT_COPIED(*s))
    188 				    {
    189 					bcopy(s, optcpy + i, olen);
    190 					i += olen;
    191 					s += olen;
    192 				    }
    193 			    }
    194 		if (i)
    195 		    {
    196 			/*
    197 			 * pad out
    198 			 */
    199 			while ((i & 3) && (i & 3) != 3)
    200 				optcpy[i++] = IPOPT_NOP;
    201 			if ((i & 3) == 3)
    202 				optcpy[i++] = IPOPT_EOL;
    203 		    }
    204 
    205 		bcopy((char *)eh, (char *)&eth, sizeof(eth));
    206 		s = (char *)ip + hlen;
    207 		iplen = ntohs(ip->ip_len) - hlen;
    208 		ip->ip_off |= htons(IP_MF);
    209 
    210 		while (1)
    211 		    {
    212 			if ((sent + (mtu - hlen)) >= iplen)
    213 			    {
    214 				ip->ip_off ^= htons(IP_MF);
    215 				ts = iplen - sent;
    216 			    }
    217 			else
    218 				ts = (mtu - hlen);
    219 			ip->ip_off &= htons(0xe000);
    220 			ip->ip_off |= htons(sent >> 3);
    221 			ts += hlen;
    222 			ip->ip_len = htons(ts);
    223 			ip->ip_sum = 0;
    224 			ip->ip_sum = chksum((u_short *)ip, hlen);
    225 			bcopy((char *)ip, ipbuf + sizeof(*eh), hlen);
    226 			bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen);
    227 			err =  sendip(nfd, ipbuf, sizeof(*eh) + ts);
    228 
    229 			bcopy((char *)&eth, ipbuf, sizeof(eth));
    230 			sent += (ts - hlen);
    231 			if (!(ntohs(ip->ip_off) & IP_MF))
    232 				break;
    233 			else if (!(ip->ip_off & htons(0x1fff)))
    234 			    {
    235 				hlen = i + sizeof(*ip);
    236 				IP_HL_A(ip, (sizeof(*ip) + i) >> 2);
    237 				bcopy(optcpy, (char *)(ip + 1), i);
    238 			    }
    239 		    }
    240 	    }
    241 
    242 	bcopy((char *)&ipsv, (char *)ip, sizeof(*ip));
    243 	return err;
    244 }
    245 
    246 
    247 /*
    248  * send a tcp packet.
    249  */
    250 int	send_tcp(nfd, mtu, ip, gwip)
    251 	int	nfd, mtu;
    252 	ip_t	*ip;
    253 	struct	in_addr	gwip;
    254 {
    255 	static	tcp_seq	iss = 2;
    256 	tcphdr_t *t, *t2;
    257 	int	thlen, i, iplen, hlen;
    258 	u_32_t	lbuf[20];
    259 	ip_t	*ip2;
    260 
    261 	iplen = ip->ip_len;
    262 	hlen = IP_HL(ip) << 2;
    263 	t = (tcphdr_t *)((char *)ip + hlen);
    264 	ip2 = (struct ip *)lbuf;
    265 	t2 = (tcphdr_t *)((char *)ip2 + sizeof(ip_t));
    266 	thlen = TCP_OFF(t) << 2;
    267 	if (!thlen)
    268 		thlen = sizeof(tcphdr_t);
    269 	bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2));
    270 	ip->ip_p = IPPROTO_TCP;
    271 	ip2->ip_p = ip->ip_p;
    272 	ip2->ip_src = ip->ip_src;
    273 	ip2->ip_dst = ip->ip_dst;
    274 	bcopy((char *)ip + hlen, (char *)t2, thlen);
    275 
    276 	if (!t2->th_win)
    277 		t2->th_win = htons(4096);
    278 	iss += 63;
    279 
    280 	i = sizeof(struct tcpiphdr) / sizeof(long);
    281 
    282 	if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) &&
    283 	    (lbuf[i] != htonl(0x020405b4))) {
    284 		lbuf[i] = htonl(0x020405b4);
    285 		bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4,
    286 		      iplen - thlen - hlen);
    287 		thlen += 4;
    288 	    }
    289 	TCP_OFF_A(t2, thlen >> 2);
    290 	ip2->ip_len = htons(thlen);
    291 	ip->ip_len = hlen + thlen;
    292 	t2->th_sum = 0;
    293 	t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t));
    294 
    295 	bcopy((char *)t2, (char *)ip + hlen, thlen);
    296 	return send_ip(nfd, mtu, ip, gwip, 1);
    297 }
    298 
    299 
    300 /*
    301  * send a udp packet.
    302  */
    303 int	send_udp(nfd, mtu, ip, gwip)
    304 	int	nfd, mtu;
    305 	ip_t	*ip;
    306 	struct	in_addr	gwip;
    307 {
    308 	struct	tcpiphdr *ti;
    309 	int	thlen;
    310 	u_long	lbuf[20];
    311 
    312 	ti = (struct tcpiphdr *)lbuf;
    313 	bzero((char *)ti, sizeof(*ti));
    314 	thlen = sizeof(udphdr_t);
    315 	ti->ti_pr = ip->ip_p;
    316 	ti->ti_src = ip->ip_src;
    317 	ti->ti_dst = ip->ip_dst;
    318 	bcopy((char *)ip + (IP_HL(ip) << 2),
    319 	      (char *)&ti->ti_sport, sizeof(udphdr_t));
    320 
    321 	ti->ti_len = htons(thlen);
    322 	ip->ip_len = (IP_HL(ip) << 2) + thlen;
    323 	ti->ti_sum = 0;
    324 	ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t));
    325 
    326 	bcopy((char *)&ti->ti_sport,
    327 	      (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t));
    328 	return send_ip(nfd, mtu, ip, gwip, 1);
    329 }
    330 
    331 
    332 /*
    333  * send an icmp packet.
    334  */
    335 int	send_icmp(nfd, mtu, ip, gwip)
    336 	int	nfd, mtu;
    337 	ip_t	*ip;
    338 	struct	in_addr	gwip;
    339 {
    340 	struct	icmp	*ic;
    341 
    342 	ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2));
    343 
    344 	ic->icmp_cksum = 0;
    345 	ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp));
    346 
    347 	return send_ip(nfd, mtu, ip, gwip, 1);
    348 }
    349 
    350 
    351 int	send_packet(nfd, mtu, ip, gwip)
    352 	int	nfd, mtu;
    353 	ip_t	*ip;
    354 	struct	in_addr	gwip;
    355 {
    356         switch (ip->ip_p)
    357         {
    358         case IPPROTO_TCP :
    359                 return send_tcp(nfd, mtu, ip, gwip);
    360         case IPPROTO_UDP :
    361                 return send_udp(nfd, mtu, ip, gwip);
    362         case IPPROTO_ICMP :
    363                 return send_icmp(nfd, mtu, ip, gwip);
    364         default :
    365                 return send_ip(nfd, mtu, ip, gwip, 1);
    366         }
    367 }
    368