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