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