11541Srgrimes 21541Srgrimes/* 31541Srgrimes * ip.c (C) 1995-1998 Darren Reed 41541Srgrimes * 51541Srgrimes * See the IPFILTER.LICENCE file for details on licencing. 61541Srgrimes */ 71541Srgrimes#include <sys/param.h> 81541Srgrimes#include <sys/types.h> 91541Srgrimes#include <netinet/in_systm.h> 101541Srgrimes#include <sys/socket.h> 111541Srgrimes#include <net/if.h> 121541Srgrimes#include <netinet/in.h> 131541Srgrimes#include <netinet/ip.h> 141541Srgrimes#include <sys/param.h> 151541Srgrimes# include <net/route.h> 161541Srgrimes# include <netinet/if_ether.h> 171541Srgrimes# include <netinet/ip_var.h> 181541Srgrimes#include <errno.h> 191541Srgrimes#include <stdio.h> 201541Srgrimes#include <stdlib.h> 211541Srgrimes#include <unistd.h> 221541Srgrimes#include <string.h> 231541Srgrimes#include "ipsend.h" 241541Srgrimes 251541Srgrimes 261541Srgrimesstatic char *ipbuf = NULL, *ethbuf = NULL; 271541Srgrimes 281541Srgrimes 291541Srgrimesu_short 301541Srgrimeschksum(u_short *buf, int len) 311541Srgrimes{ 321541Srgrimes u_long sum = 0; 331541Srgrimes int nwords = len >> 1; 341541Srgrimes 351541Srgrimes for(; nwords > 0; nwords--) 361541Srgrimes sum += *buf++; 371541Srgrimes sum = (sum>>16) + (sum & 0xffff); 3814486Shsu sum += (sum >>16); 3950477Speter return (~sum); 401541Srgrimes} 411541Srgrimes 421541Srgrimes 431541Srgrimesint 441541Srgrimessend_ether(int nfd, char *buf, int len, struct in_addr gwip) 459343Sbde{ 4634925Sdufault static struct in_addr last_gw; 479343Sbde static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 4851791Smarcel ether_header_t *eh; 4951942Smarcel char *s; 5051791Smarcel int err; 5151942Smarcel 5251942Smarcel if (!ethbuf) 5351942Smarcel ethbuf = (char *)calloc(1, 65536+1024); 5451942Smarcel s = ethbuf; 5551942Smarcel eh = (ether_header_t *)s; 5675682Salfred 571541Srgrimes bcopy((char *)buf, s + sizeof(*eh), len); 5851791Smarcel if (gwip.s_addr == last_gw.s_addr) 5951942Smarcel { 6051791Smarcel bcopy(last_arp, (char *) &eh->ether_dhost, 6); 6151942Smarcel } 6251791Smarcel else if (arp((char *)&gwip, (char *) &eh->ether_dhost) == -1) 6351791Smarcel { 6451791Smarcel perror("arp"); 651541Srgrimes return (-2); 6651791Smarcel } 671541Srgrimes eh->ether_type = htons(ETHERTYPE_IP); 6851791Smarcel last_gw.s_addr = gwip.s_addr; 691541Srgrimes err = sendip(nfd, s, sizeof(*eh) + len); 7051791Smarcel return (err); 7151791Smarcel} 721541Srgrimes 7351791Smarcel 7451791Smarcel/* 751541Srgrimes */ 7651791Smarcelint 771541Srgrimessend_ip(int nfd, int mtu, ip_t *ip, struct in_addr gwip, int frag) 7851791Smarcel{ 791541Srgrimes static struct in_addr last_gw, local_ip; 8051791Smarcel static char local_arp[6] = { 0, 0, 0, 0, 0, 0}; 811541Srgrimes static char last_arp[6] = { 0, 0, 0, 0, 0, 0}; 8251791Smarcel static u_short id = 0; 8351791Smarcel ether_header_t *eh; 8451791Smarcel ip_t ipsv; 851541Srgrimes int err, iplen; 8651791Smarcel 871541Srgrimes if (!ipbuf) 8851791Smarcel { 8951791Smarcel ipbuf = (char *)malloc(65536); 9051791Smarcel if (!ipbuf) 9151791Smarcel { 9251791Smarcel perror("malloc failed"); 9351791Smarcel return (-2); 941541Srgrimes } 9551791Smarcel } 9651791Smarcel 9751791Smarcel eh = (ether_header_t *)ipbuf; 9851791Smarcel 9951791Smarcel bzero((char *) &eh->ether_shost, sizeof(eh->ether_shost)); 10051942Smarcel if (last_gw.s_addr && (gwip.s_addr == last_gw.s_addr)) 10151942Smarcel { 1021541Srgrimes bcopy(last_arp, (char *) &eh->ether_dhost, 6); 10351942Smarcel } 10451942Smarcel else if (arp((char *)&gwip, (char *) &eh->ether_dhost) == -1) 1051541Srgrimes { 1069343Sbde perror("arp"); 1079343Sbde return (-2); 1089343Sbde } 1099343Sbde bcopy((char *) &eh->ether_dhost, last_arp, sizeof(last_arp)); 1101541Srgrimes eh->ether_type = htons(ETHERTYPE_IP); 1119343Sbde 1129343Sbde bcopy((char *)ip, (char *)&ipsv, sizeof(*ip)); 1139343Sbde last_gw.s_addr = gwip.s_addr; 1149343Sbde iplen = ip->ip_len; 1159343Sbde ip->ip_len = htons(iplen); 1169343Sbde if (!(frag & 2)) { 1179343Sbde if (!IP_V(ip)) 1189343Sbde IP_V_A(ip, IPVERSION); 1199343Sbde if (!ip->ip_id) 1209343Sbde ip->ip_id = htons(id++); 1211541Srgrimes if (!ip->ip_ttl) 1229343Sbde ip->ip_ttl = 60; 1231541Srgrimes } 12451791Smarcel 12551791Smarcel if (ip->ip_src.s_addr != local_ip.s_addr) { 12651791Smarcel (void) arp((char *)&ip->ip_src, (char *) &local_arp); 12751791Smarcel bcopy(local_arp, (char *) &eh->ether_shost,sizeof(last_arp)); 12855205Speter local_ip = ip->ip_src; 12948621Scracauer } else 13048621Scracauer bcopy(local_arp, (char *) &eh->ether_shost, 6); 13151942Smarcel 13251942Smarcel if (!frag || (sizeof(*eh) + iplen < mtu)) 13348621Scracauer { 13448621Scracauer ip->ip_sum = 0; 13552308Smarcel ip->ip_sum = chksum((u_short *)ip, IP_HL(ip) << 2); 13652308Smarcel 13769002Salc bcopy((char *)ip, ipbuf + sizeof(*eh), iplen); 13869002Salc err = sendip(nfd, ipbuf, sizeof(*eh) + iplen); 13969002Salc } 14069002Salc else 14152308Smarcel { 14252308Smarcel /* 14369002Salc * Actually, this is bogus because we're putting all IP 14469002Salc * options in every packet, which isn't always what should be 14552308Smarcel * done. Will do for now. 14652308Smarcel */ 14752308Smarcel ether_header_t eth; 14869002Salc char optcpy[48], ol; 14952308Smarcel char *s; 15051942Smarcel int i, sent = 0, ts, hlen, olen; 15151942Smarcel 15251942Smarcel hlen = IP_HL(ip) << 2; 15352160Smarcel if (mtu < (hlen + 8)) { 15448621Scracauer fprintf(stderr, "mtu (%d) < ip header size (%d) + 8\n", 15548621Scracauer mtu, hlen); 15648621Scracauer fprintf(stderr, "can't fragment data\n"); 15748621Scracauer return (-2); 15848621Scracauer } 15951942Smarcel ol = (IP_HL(ip) << 2) - sizeof(*ip); 16051942Smarcel for (i = 0, s = (char*)(ip + 1); ol > 0; ) 16151942Smarcel if (*s == IPOPT_EOL) { 16251942Smarcel optcpy[i++] = *s; 16351942Smarcel break; 16451942Smarcel } else if (*s == IPOPT_NOP) { 16551942Smarcel s++; 16651942Smarcel ol--; 16751791Smarcel } else 16852096Smarcel { 16948621Scracauer olen = (int)(*(u_char *)(s + 1)); 17051942Smarcel ol -= olen; 17151791Smarcel if (IPOPT_COPIED(*s)) 17251791Smarcel { 17348621Scracauer bcopy(s, optcpy + i, olen); 17451942Smarcel i += olen; 17552160Smarcel s += olen; 17652160Smarcel } 17751942Smarcel } 17851942Smarcel if (i) 17951942Smarcel { 18051791Smarcel /* 18148621Scracauer * pad out 18251942Smarcel */ 18351942Smarcel while ((i & 3) && (i & 3) != 3) 1841541Srgrimes optcpy[i++] = IPOPT_NOP; 1851541Srgrimes if ((i & 3) == 3) 1861541Srgrimes optcpy[i++] = IPOPT_EOL; 18783045Sobrien } 18848621Scracauer 18948621Scracauer bcopy((char *)eh, (char *)ð, sizeof(eth)); 19051942Smarcel s = (char *)ip + hlen; 19151942Smarcel iplen = ntohs(ip->ip_len) - hlen; 19248621Scracauer ip->ip_off |= htons(IP_MF); 19351942Smarcel 19451942Smarcel while (1) 1951541Srgrimes { 19651791Smarcel if ((sent + (mtu - hlen)) >= iplen) 19748621Scracauer { 19848621Scracauer ip->ip_off ^= htons(IP_MF); 19951791Smarcel ts = iplen - sent; 20051791Smarcel } 20151791Smarcel else 20251791Smarcel ts = (mtu - hlen); 20351791Smarcel ip->ip_off &= htons(0xe000); 20448621Scracauer ip->ip_off |= htons(sent >> 3); 20548621Scracauer ts += hlen; 2061541Srgrimes ip->ip_len = htons(ts); 2079343Sbde ip->ip_sum = 0; 20814331Speter ip->ip_sum = chksum((u_short *)ip, hlen); 20914331Speter bcopy((char *)ip, ipbuf + sizeof(*eh), hlen); 21029340Sjoerg bcopy(s + sent, ipbuf + sizeof(*eh) + hlen, ts - hlen); 21148621Scracauer err = sendip(nfd, ipbuf, sizeof(*eh) + ts); 2121541Srgrimes 2131541Srgrimes bcopy((char *)ð, ipbuf, sizeof(eth)); 2141541Srgrimes sent += (ts - hlen); 2151541Srgrimes if (!(ntohs(ip->ip_off) & IP_MF)) 21651942Smarcel break; 2171541Srgrimes else if (!(ip->ip_off & htons(0x1fff))) 21851791Smarcel { 21951791Smarcel hlen = i + sizeof(*ip); 22051791Smarcel IP_HL_A(ip, (sizeof(*ip) + i) >> 2); 22151791Smarcel bcopy(optcpy, (char *)(ip + 1), i); 22251791Smarcel } 22351791Smarcel } 22451791Smarcel } 22551791Smarcel 22651791Smarcel bcopy((char *)&ipsv, (char *)ip, sizeof(*ip)); 22751791Smarcel return (err); 22852308Smarcel} 22951791Smarcel 2309343Sbde 2311541Srgrimes/* 23238121Sdfr * send a tcp packet. 23338121Sdfr */ 23438121Sdfrint 23538121Sdfrsend_tcp(int nfd, int mtu, ip_t *ip, struct in_addr gwip) 23638121Sdfr{ 2371541Srgrimes static tcp_seq iss = 2; 23851942Smarcel tcphdr_t *t, *t2; 2391541Srgrimes int thlen, i, iplen, hlen; 24051791Smarcel u_32_t lbuf[20]; 24151942Smarcel ip_t *ip2; 24251942Smarcel 24351942Smarcel iplen = ip->ip_len; 24451791Smarcel hlen = IP_HL(ip) << 2; 24551791Smarcel t = (tcphdr_t *)((char *)ip + hlen); 24614331Speter ip2 = (struct ip *)lbuf; 24714331Speter t2 = (tcphdr_t *)((char *)ip2 + hlen); 2481541Srgrimes thlen = TCP_OFF(t) << 2; 2491541Srgrimes if (!thlen) 25051942Smarcel thlen = sizeof(tcphdr_t); 25151791Smarcel bzero((char *)ip2, sizeof(*ip2) + sizeof(*t2)); 25251791Smarcel ip->ip_p = IPPROTO_TCP; 25351791Smarcel ip2->ip_p = ip->ip_p; 2541541Srgrimes ip2->ip_src = ip->ip_src; 2551541Srgrimes ip2->ip_dst = ip->ip_dst; 2561541Srgrimes bcopy((char *)ip + hlen, (char *)t2, thlen); 25783045Sobrien 25851942Smarcel if (!t2->th_win) 25951942Smarcel t2->th_win = htons(4096); 26051942Smarcel iss += 63; 2611541Srgrimes 2621541Srgrimes i = sizeof(struct tcpiphdr) / sizeof(long); 2631541Srgrimes 2641541Srgrimes if ((t2->th_flags == TH_SYN) && !ntohs(ip->ip_off) && 26514331Speter (lbuf[i] != htonl(0x020405b4))) { 26614927Speter lbuf[i] = htonl(0x020405b4); 26714927Speter bcopy((char *)ip + hlen + thlen, (char *)ip + hlen + thlen + 4, 26848621Scracauer iplen - thlen - hlen); 2691541Srgrimes thlen += 4; 2701541Srgrimes } 2711541Srgrimes TCP_OFF_A(t2, thlen >> 2); 2721541Srgrimes ip2->ip_len = htons(thlen); 2731541Srgrimes ip->ip_len = hlen + thlen; 27483045Sobrien t2->th_sum = 0; 27551942Smarcel t2->th_sum = chksum((u_short *)ip2, thlen + sizeof(ip_t)); 27651942Smarcel 2771541Srgrimes bcopy((char *)t2, (char *)ip + hlen, thlen); 2781541Srgrimes return (send_ip(nfd, mtu, ip, gwip, 1)); 2791541Srgrimes} 2801541Srgrimes 2811541Srgrimes 2821541Srgrimes/* 2831541Srgrimes * send a udp packet. 2841541Srgrimes */ 2851541Srgrimesint 2861541Srgrimessend_udp(int nfd, int mtu, ip_t *ip, struct in_addr gwip) 28751791Smarcel{ 2881541Srgrimes struct tcpiphdr *ti; 28951791Smarcel int thlen; 29051791Smarcel u_long lbuf[20]; 29151791Smarcel 29251791Smarcel ti = (struct tcpiphdr *)lbuf; 29351791Smarcel bzero((char *)ti, sizeof(*ti)); 29451791Smarcel thlen = sizeof(udphdr_t); 29534925Sdufault ti->ti_pr = ip->ip_p; 29651791Smarcel ti->ti_src = ip->ip_src; 29734925Sdufault ti->ti_dst = ip->ip_dst; 2981541Srgrimes bcopy((char *)ip + (IP_HL(ip) << 2), 2991541Srgrimes (char *)&ti->ti_sport, sizeof(udphdr_t)); 3001541Srgrimes 3011541Srgrimes ti->ti_len = htons(thlen); 3021541Srgrimes ip->ip_len = (IP_HL(ip) << 2) + thlen; 3039343Sbde ti->ti_sum = 0; 3041541Srgrimes ti->ti_sum = chksum((u_short *)ti, thlen + sizeof(ip_t)); 3059343Sbde 3061541Srgrimes bcopy((char *)&ti->ti_sport, 307 (char *)ip + (IP_HL(ip) << 2), sizeof(udphdr_t)); 308 return (send_ip(nfd, mtu, ip, gwip, 1)); 309} 310 311 312/* 313 * send an icmp packet. 314 */ 315int 316send_icmp(int nfd, int mtu, ip_t *ip, in_addr gwip) 317{ 318 struct icmp *ic; 319 320 ic = (struct icmp *)((char *)ip + (IP_HL(ip) << 2)); 321 322 ic->icmp_cksum = 0; 323 ic->icmp_cksum = chksum((u_short *)ic, sizeof(struct icmp)); 324 325 return (send_ip(nfd, mtu, ip, gwip, 1)); 326} 327 328 329int 330send_packet(int nfd, int mtu, ip_t *ip, struct in_addr gwip) 331 int nfd, mtu; 332 ip_t *ip; 333 struct in_addr gwip; 334{ 335 switch (ip->ip_p) 336 { 337 case IPPROTO_TCP : 338( return send_tcp(nfd, mtu, ip, gwip)); 339 case IPPROTO_UDP : 340( return send_udp(nfd, mtu, ip, gwip)); 341 case IPPROTO_ICMP : 342( return send_icmp(nfd, mtu, ip, gwip)); 343 default : 344( return send_ip(nfd, mtu, ip, gwip, 1)); 345 } 346} 347