ip.c revision 31143
17465Sache/* 22893Sdfr * PPP IP Protocol Interface 32893Sdfr * 42893Sdfr * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 52893Sdfr * 62893Sdfr * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 72893Sdfr * 82893Sdfr * Redistribution and use in source and binary forms are permitted 92893Sdfr * provided that the above copyright notice and this paragraph are 102893Sdfr * duplicated in all such forms and that any documentation, 112893Sdfr * advertising materials, and other materials related to such 122893Sdfr * distribution and use acknowledge that the software was developed 132893Sdfr * by the Internet Initiative Japan. The name of the 142893Sdfr * IIJ may not be used to endorse or promote products derived 152893Sdfr * from this software without specific prior written permission. 162893Sdfr * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 172893Sdfr * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 182893Sdfr * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 192893Sdfr * 202893Sdfr * $Id: ip.c,v 1.28 1997/11/12 19:48:45 brian Exp $ 212893Sdfr * 222893Sdfr * TODO: 232893Sdfr * o Return ICMP message for filterd packet 242893Sdfr * and optionaly record it into log. 252893Sdfr */ 263152Sphk#include <sys/param.h> 277465Sache#include <netinet/in.h> 282893Sdfr#include <netinet/in_systm.h> 292893Sdfr#include <netinet/ip.h> 302893Sdfr#include <netinet/ip_icmp.h> 312893Sdfr#include <netinet/udp.h> 322893Sdfr#include <netinet/tcp.h> 332893Sdfr#include <arpa/inet.h> 342893Sdfr 357465Sache#include <alias.h> 362893Sdfr#include <errno.h> 372893Sdfr#include <stdio.h> 387465Sache#include <stdlib.h> 397465Sache#include <string.h> 402893Sdfr#include <termios.h> 412893Sdfr#include <unistd.h> 422893Sdfr 437465Sache#include "mbuf.h" 442893Sdfr#include "log.h" 452893Sdfr#include "defs.h" 467465Sache#include "timer.h" 477465Sache#include "fsm.h" 482893Sdfr#include "lcpproto.h" 492893Sdfr#include "hdlc.h" 502893Sdfr#include "loadalias.h" 512893Sdfr#include "command.h" 522893Sdfr#include "vars.h" 532893Sdfr#include "filter.h" 542893Sdfr#include "log.h" 552893Sdfr#include "os.h" 562893Sdfr#include "ipcp.h" 572893Sdfr#include "vjcomp.h" 582893Sdfr#include "lcp.h" 592893Sdfr#include "modem.h" 602893Sdfr#include "ip.h" 612893Sdfr 622893Sdfrstatic struct pppTimer IdleTimer; 632893Sdfr 642893Sdfrstatic void 652893SdfrIdleTimeout() 662893Sdfr{ 672893Sdfr LogPrintf(LogPHASE, "Idle timer expired.\n"); 682893Sdfr reconnect(RECON_FALSE); 692893Sdfr LcpClose(); 702893Sdfr} 712893Sdfr 722893Sdfr/* 732893Sdfr * Start Idle timer. If timeout is reached, we call LcpClose() to 742893Sdfr * close LCP and link. 752893Sdfr */ 762893Sdfrvoid 772893SdfrStartIdleTimer() 782893Sdfr{ 792893Sdfr if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 807465Sache StopTimer(&IdleTimer); 812893Sdfr IdleTimer.func = IdleTimeout; 822893Sdfr IdleTimer.load = VarIdleTimeout * SECTICKS; 832893Sdfr IdleTimer.state = TIMER_STOPPED; 842893Sdfr StartTimer(&IdleTimer); 852893Sdfr } 862893Sdfr} 872893Sdfr 882893Sdfrvoid 892893SdfrUpdateIdleTimer() 902893Sdfr{ 912893Sdfr if (OsLinkIsUp()) 922893Sdfr StartIdleTimer(); 932893Sdfr} 942893Sdfr 952893Sdfrvoid 962893SdfrStopIdleTimer() 972893Sdfr{ 982893Sdfr StopTimer(&IdleTimer); 992893Sdfr} 1002893Sdfr 1012893Sdfr/* 1022893Sdfr * If any IP layer traffic is detected, refresh IdleTimer. 1037465Sache */ 1047465Sachestatic void 1057465SacheRestartIdleTimer() 1067465Sache{ 1072893Sdfr if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 1082893Sdfr StartTimer(&IdleTimer); 1092893Sdfr ipIdleSecs = 0; 1102893Sdfr } 1112893Sdfr} 1122893Sdfr 1132893Sdfrstatic u_short interactive_ports[32] = { 1142893Sdfr 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1152893Sdfr 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 1162893Sdfr}; 1172893Sdfr 1182893Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 1192893Sdfr 1202893Sdfrstatic char *TcpFlags[] = { 1212893Sdfr "FIN", "SYN", "RST", "PSH", "ACK", "URG", 1222893Sdfr}; 1232893Sdfr 1242893Sdfrstatic char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 1252893Sdfrstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 1262893Sdfr 1272893Sdfrstatic int 1282893SdfrPortMatch(int op, u_short pport, u_short rport) 1292893Sdfr{ 1302893Sdfr switch (op) { 1312893Sdfr case OP_EQ: 1322893Sdfr return (pport == rport); 1332893Sdfr case OP_GT: 1342893Sdfr return (pport > rport); 1352893Sdfr case OP_LT: 1362893Sdfr return (pport < rport); 1372893Sdfr default: 1382893Sdfr return (0); 1392893Sdfr } 1402893Sdfr} 1412893Sdfr 1422893Sdfr/* 1432893Sdfr * Check a packet against with defined filters 1442893Sdfr */ 1452893Sdfrstatic int 1462893SdfrFilterCheck(struct ip * pip, int direction) 1472893Sdfr{ 1482893Sdfr struct filterent *fp = Filters[direction]; 1495083Sbde int gotinfo, cproto, estab, n; 1502893Sdfr struct tcphdr *th; 1512893Sdfr struct udphdr *uh; 1522893Sdfr struct icmp *ih; 1532893Sdfr char *ptop; 1542893Sdfr u_short sport, dport; 1552893Sdfr 1562893Sdfr if (fp->action) { 1572893Sdfr cproto = gotinfo = estab = 0; 1582893Sdfr sport = dport = 0; 1592893Sdfr for (n = 0; n < MAXFILTERS; n++) { 1607465Sache if (fp->action) { 1617465Sache /* permit fragments on in and out filter */ 1627465Sache if ((direction == FL_IN || direction == FL_OUT) && 1637465Sache (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 1642893Sdfr return (A_PERMIT); 1652893Sdfr } 1667465Sache LogPrintf(LogDEBUG, "rule = %d\n", n); 1673152Sphk if ((pip->ip_src.s_addr & fp->smask.s_addr) == 1683152Sphk (fp->saddr.s_addr & fp->smask.s_addr) && 1693152Sphk (pip->ip_dst.s_addr & fp->dmask.s_addr) == 1702893Sdfr (fp->daddr.s_addr & fp->dmask.s_addr)) { 1712893Sdfr if (fp->proto) { 1727465Sache if (!gotinfo) { 1737465Sache ptop = (char *) pip + (pip->ip_hl << 2); 1742893Sdfr 1752893Sdfr switch (pip->ip_p) { 1762893Sdfr case IPPROTO_ICMP: 1772893Sdfr cproto = P_ICMP; 1787465Sache ih = (struct icmp *) ptop; 1792893Sdfr sport = ih->icmp_type; 1802893Sdfr estab = 1; 1812893Sdfr break; 1822893Sdfr case IPPROTO_UDP: 1832893Sdfr cproto = P_UDP; 1842893Sdfr uh = (struct udphdr *) ptop; 1852893Sdfr sport = ntohs(uh->uh_sport); 1862893Sdfr dport = ntohs(uh->uh_dport); 1872893Sdfr estab = 1; 1882893Sdfr break; 1892893Sdfr case IPPROTO_TCP: 1902893Sdfr cproto = P_TCP; 1912893Sdfr th = (struct tcphdr *) ptop; 1922893Sdfr sport = ntohs(th->th_sport); 1932893Sdfr dport = ntohs(th->th_dport); 1942893Sdfr estab = (th->th_flags & TH_ACK); 1952893Sdfr if (estab == 0) 1962893Sdfr LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 1972893Sdfr th->th_flags, sport, dport); 1982893Sdfr break; 1992893Sdfr default: 2002893Sdfr return (A_DENY);/* We'll block unknown type of packet */ 2012893Sdfr } 2022893Sdfr gotinfo = 1; 2032893Sdfr LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 2042893Sdfr " dstop = %d, estab = %d\n", direction, cproto, 2052893Sdfr fp->opt.srcop, fp->opt.dstop, estab); 2062893Sdfr } 2072893Sdfr LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 2082893Sdfr " dport = %d\n", n, cproto, sport, dport); 2092893Sdfr LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 2102893Sdfr 2112893Sdfr if (cproto == fp->proto) { 2122893Sdfr if ((fp->opt.srcop == OP_NONE || 2132893Sdfr PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 2142893Sdfr && 2152893Sdfr (fp->opt.dstop == OP_NONE || 2162893Sdfr PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 2172893Sdfr && 2182893Sdfr (fp->opt.estab == 0 || estab)) { 2192893Sdfr return (fp->action); 2202893Sdfr } 2212893Sdfr } 2222893Sdfr } else { 2232893Sdfr /* Address is mached. Make a decision. */ 2242893Sdfr LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 2252893Sdfr return (fp->action); 2262893Sdfr } 2272893Sdfr } 2282893Sdfr } 2292893Sdfr fp++; 2302893Sdfr } 2312893Sdfr return (A_DENY); /* No rule is mached. Deny this packet */ 2322893Sdfr } 2332893Sdfr return (A_PERMIT); /* No rule is given. Permit this packet */ 2342893Sdfr} 2352893Sdfr 2362893Sdfrstatic void 2372893SdfrIcmpError(struct ip * pip, int code) 2382893Sdfr{ 2392893Sdfr#ifdef notdef 2402893Sdfr struct mbuf *bp; 2412893Sdfr 2422893Sdfr if (pip->ip_p != IPPROTO_ICMP) { 2432893Sdfr bp = mballoc(cnt, MB_IPIN); 2442893Sdfr memcpy(MBUF_CTOP(bp), ptr, cnt); 2452893Sdfr SendPppFrame(bp); 2462893Sdfr RestartIdleTimer(); 2472893Sdfr ipOutOctets += cnt; 2482893Sdfr } 2492893Sdfr#endif 2502893Sdfr} 2512893Sdfr 2522893Sdfr/* 2532893Sdfr * For debugging aid. 2542893Sdfr */ 2552893Sdfrint 2562893SdfrPacketCheck(char *cp, int nb, int direction) 2572893Sdfr{ 2582893Sdfr struct ip *pip; 2592893Sdfr struct tcphdr *th; 2602893Sdfr struct udphdr *uh; 2612893Sdfr struct icmp *icmph; 2622893Sdfr char *ptop; 2632893Sdfr int mask, len, n; 2642893Sdfr int pri = PRI_NORMAL; 2652893Sdfr int logit, loglen; 2662893Sdfr static char logbuf[200]; 2672893Sdfr 2682893Sdfr logit = LogIsKept(LogTCPIP); 2692893Sdfr loglen = 0; 2702893Sdfr 2712893Sdfr pip = (struct ip *) cp; 2722893Sdfr 2732893Sdfr if (logit && loglen < sizeof logbuf) { 2742893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 2752893Sdfr Direction[direction]); 2762893Sdfr loglen += strlen(logbuf + loglen); 2772893Sdfr } 2782893Sdfr ptop = (cp + (pip->ip_hl << 2)); 2792893Sdfr 2802893Sdfr switch (pip->ip_p) { 2812893Sdfr case IPPROTO_ICMP: 2822893Sdfr if (logit && loglen < sizeof logbuf) { 2832893Sdfr icmph = (struct icmp *) ptop; 2842893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, 2852893Sdfr "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 2862893Sdfr loglen += strlen(logbuf + loglen); 2872893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, 2882893Sdfr "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 2892893Sdfr loglen += strlen(logbuf + loglen); 2902893Sdfr } 2912893Sdfr break; 2922893Sdfr case IPPROTO_UDP: 2932893Sdfr if (logit && loglen < sizeof logbuf) { 2942893Sdfr uh = (struct udphdr *) ptop; 2952893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, 2962893Sdfr "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 2972893Sdfr loglen += strlen(logbuf + loglen); 2982893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, 2992893Sdfr "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 3002893Sdfr loglen += strlen(logbuf + loglen); 3012893Sdfr } 3022893Sdfr break; 3032893Sdfr case IPPROTO_TCP: 3042893Sdfr th = (struct tcphdr *) ptop; 3052893Sdfr if (pip->ip_tos == IPTOS_LOWDELAY) 3062893Sdfr pri = PRI_FAST; 3072893Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 3082893Sdfr if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 3092893Sdfr pri = PRI_FAST; 3102893Sdfr } 3112893Sdfr if (logit && loglen < sizeof logbuf) { 3122893Sdfr len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 3132893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, 3142893Sdfr "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 3152893Sdfr loglen += strlen(logbuf + loglen); 3162893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, 3172893Sdfr "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 3182893Sdfr loglen += strlen(logbuf + loglen); 3192893Sdfr n = 0; 3202893Sdfr for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 3212893Sdfr if (th->th_flags & mask) { 3222893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 3232893Sdfr loglen += strlen(logbuf + loglen); 3242893Sdfr } 3252893Sdfr n++; 3262893Sdfr } 3272893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, 3282893Sdfr " seq:%x ack:%x (%d/%d)", 3292893Sdfr ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 3302893Sdfr loglen += strlen(logbuf + loglen); 3312893Sdfr if ((th->th_flags & TH_SYN) && nb > 40) { 3322893Sdfr u_short *sp; 3332893Sdfr 3342893Sdfr ptop += 20; 3352893Sdfr sp = (u_short *) ptop; 3362893Sdfr if (ntohs(sp[0]) == 0x0204) { 3372893Sdfr snprintf(logbuf + loglen, sizeof logbuf - loglen, 3382893Sdfr " MSS = %d", ntohs(sp[1])); 3392893Sdfr loglen += strlen(logbuf + loglen); 3402893Sdfr } 3412893Sdfr } 3422893Sdfr } 3432893Sdfr break; 3442893Sdfr } 3452893Sdfr 3462893Sdfr if ((FilterCheck(pip, direction) & A_DENY)) { 3472893Sdfr if (logit) 3482893Sdfr LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf); 3492893Sdfr if (direction == 0) 3502893Sdfr IcmpError(pip, pri); 3512893Sdfr return (-1); 3522893Sdfr } else { 3532893Sdfr if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 3542893Sdfr if (logit) 3552893Sdfr LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 3562893Sdfr ipKeepAlive = 0; 357 } else { 358 if (logit) 359 LogPrintf(LogTCPIP, "%s\n", logbuf); 360 ipKeepAlive = 1; 361 } 362 return (pri); 363 } 364} 365 366void 367IpInput(struct mbuf * bp) 368{ /* IN: Pointer to IP pakcet */ 369 u_char *cp; 370 struct mbuf *wp; 371 int nb, nw; 372 u_char tunbuff[MAX_MRU]; 373 374 cp = tunbuff; 375 nb = 0; 376 for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 377 memcpy(cp, MBUF_CTOP(wp), wp->cnt); 378 cp += wp->cnt; 379 nb += wp->cnt; 380 } 381 382 if (mode & MODE_ALIAS) { 383 int iresult; 384 char *fptr; 385 386 iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff); 387 nb = ntohs(((struct ip *) tunbuff)->ip_len); 388 389 if (nb > MAX_MRU) { 390 LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 391 pfree(bp); 392 return; 393 } 394 if (iresult == PKT_ALIAS_OK 395 || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 396 if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 397 pfree(bp); 398 return; 399 } 400 ipInOctets += nb; 401 402 nb = ntohs(((struct ip *) tunbuff)->ip_len); 403 nw = write(tun_out, tunbuff, nb); 404 if (nw != nb) 405 if (nw == -1) 406 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 407 strerror(errno)); 408 else 409 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 410 411 if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 412 while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) { 413 VarPacketAliasFragmentIn(tunbuff, fptr); 414 nb = ntohs(((struct ip *) fptr)->ip_len); 415 nw = write(tun_out, fptr, nb); 416 if (nw != nb) 417 if (nw == -1) 418 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 419 strerror(errno)); 420 else 421 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 422 free(fptr); 423 } 424 } 425 } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 426 nb = ntohs(((struct ip *) tunbuff)->ip_len); 427 fptr = malloc(nb); 428 if (fptr == NULL) 429 LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 430 else { 431 memcpy(fptr, tunbuff, nb); 432 VarPacketAliasSaveFragment(fptr); 433 } 434 } 435 } else { /* no aliasing */ 436 if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 437 pfree(bp); 438 return; 439 } 440 ipInOctets += nb; 441 nw = write(tun_out, tunbuff, nb); 442 if (nw != nb) 443 if (nw == -1) 444 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 445 else 446 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 447 } 448 pfree(bp); 449 450 RestartIdleTimer(); 451} 452 453static struct mqueue IpOutputQueues[PRI_FAST + 1]; 454 455void 456IpEnqueue(int pri, char *ptr, int count) 457{ 458 struct mbuf *bp; 459 460 bp = mballoc(count, MB_IPQ); 461 memcpy(MBUF_CTOP(bp), ptr, count); 462 Enqueue(&IpOutputQueues[pri], bp); 463} 464 465#if 0 466int 467IsIpEnqueued() 468{ 469 struct mqueue *queue; 470 int exist = 0; 471 472 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 473 if (queue->qlen > 0) { 474 exist = 1; 475 break; 476 } 477 } 478 return (exist); 479} 480#endif 481 482void 483IpStartOutput() 484{ 485 struct mqueue *queue; 486 struct mbuf *bp; 487 int cnt; 488 489 if (IpcpFsm.state != ST_OPENED) 490 return; 491 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 492 if (queue->top) { 493 bp = Dequeue(queue); 494 if (bp) { 495 cnt = plength(bp); 496 SendPppFrame(bp); 497 RestartIdleTimer(); 498 ipOutOctets += cnt; 499 break; 500 } 501 } 502 } 503} 504