ip.c revision 8857
16059Samurai/*
26059Samurai *		PPP IP Protocol Interface
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198857Srgrimes *
208857Srgrimes * $Id: ip.c,v 1.3 1995/03/11 15:18:42 amurai Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Return ICMP message for filterd packet
246059Samurai *		  and optionaly record it into log.
256059Samurai */
266059Samurai#include "fsm.h"
276059Samurai#include "lcpproto.h"
286059Samurai#include "hdlc.h"
296059Samurai#include <netinet/in_systm.h>
306059Samurai#include <netinet/ip.h>
316059Samurai#include <netinet/ip_icmp.h>
326059Samurai#include <netinet/udp.h>
336059Samurai#include <netinet/tcp.h>
346059Samurai#include "vars.h"
356059Samurai#include "filter.h"
366059Samurai
376735Samuraiextern void SendPppFrame();
386059Samuraiextern int PacketCheck();
396059Samuraiextern void LcpClose();
406059Samurai
416059Samuraistatic struct pppTimer IdleTimer;
426059Samurai
436059Samuraistatic void IdleTimeout()
446059Samurai{
456059Samurai  LogPrintf(LOG_PHASE, "Idle timer expired.\n");
466059Samurai  LcpClose();
476059Samurai}
486059Samurai
496059Samurai/*
506059Samurai *  Start Idle timer. If timeout is reached, we call LcpClose() to
516059Samurai *  close LCP and link.
526059Samurai */
536059Samuraivoid
546059SamuraiStartIdleTimer()
556059Samurai{
566059Samurai  if (!(mode & MODE_DEDICATED)) {
576059Samurai    StopTimer(&IdleTimer);
586059Samurai    IdleTimer.func = IdleTimeout;
596059Samurai    IdleTimer.load = VarIdleTimeout * SECTICKS;
606059Samurai    IdleTimer.state = TIMER_STOPPED;
616059Samurai    StartTimer(&IdleTimer);
626059Samurai  }
636059Samurai}
646059Samurai
656059Samuraivoid
666059SamuraiStopIdleTimer()
676059Samurai{
686059Samurai  StopTimer(&IdleTimer);
696059Samurai}
706059Samurai
716059Samurai/*
726059Samurai *  If any IP layer traffic is detected, refresh IdleTimer.
736059Samurai */
746059Samuraistatic void
756059SamuraiRestartIdleTimer()
766059Samurai{
776735Samurai  if (!(mode & MODE_DEDICATED) && ipKeepAlive ) {
786059Samurai    StartTimer(&IdleTimer);
796059Samurai    ipIdleSecs = 0;
806059Samurai  }
816059Samurai}
826059Samurai
836059Samuraistatic u_short interactive_ports[8] = {
846059Samurai  0, 513, 0, 0, 0, 21, 0, 23,
856059Samurai};
866059Samurai
876059Samurai#define	INTERACTIVE(p)	(interactive_ports[(p) & 7] == (p))
886059Samurai
896059Samuraistatic char *TcpFlags[] = {
906059Samurai  "FIN", "SYN", "RST", "PSH", "ACK", "URG",
916059Samurai};
926059Samurai
936735Samuraistatic char *Direction[] = { "INP", "OUT", "OUT", "IN/OUT" };
946735Samuraistatic struct filterent *Filters[] = { ifilters, ofilters, dfilters, afilters };
956059Samurai
966059Samuraistatic int
976059SamuraiPortMatch(op, pport, rport)
986059Samuraiint op;
996059Samuraiu_short pport, rport;
1006059Samurai{
1016059Samurai  switch (op) {
1026059Samurai  case OP_EQ:
1036059Samurai    return(pport == rport);
1046059Samurai  case OP_GT:
1056059Samurai    return(pport > rport);
1066059Samurai  case OP_LT:
1076059Samurai    return(pport < rport);
1086059Samurai  default:
1096059Samurai    return(0);
1106059Samurai  }
1116059Samurai}
1126059Samurai
1136059Samurai/*
1146059Samurai *  Check a packet against with defined filters
1156059Samurai */
1166059Samuraistatic int
1176059SamuraiFilterCheck(pip, direction)
1186059Samuraistruct ip *pip;
1196059Samuraiint direction;
1206059Samurai{
1216059Samurai  struct filterent *fp = Filters[direction];
1226059Samurai  int gotinfo, cproto, estab, n;
1236059Samurai  struct tcphdr *th;
1246059Samurai  struct udphdr *uh;
1256059Samurai  struct icmp *ih;
1266059Samurai  char *ptop;
1276059Samurai  u_short sport, dport;
1286059Samurai
1296059Samurai  if (fp->action) {
1306059Samurai    cproto = gotinfo = estab = 0;
1316059Samurai    sport = dport = 0;
1326059Samurai    for (n = 0; n < MAXFILTERS; n++) {
1336059Samurai      if (fp->action) {
1346059Samurai#ifdef DEBUG
1356059Samurailogprintf("rule = %d\n", n);
1366059Samurai#endif
1376059Samurai	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
1386059Samurai	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
1396059Samurai	  if (fp->proto) {
1406059Samurai	    if (!gotinfo) {
1416059Samurai	      ptop = (char *)pip + (pip->ip_hl << 2);
1426059Samurai
1436059Samurai	      switch (pip->ip_p) {
1446059Samurai	      case IPPROTO_ICMP:
1456059Samurai		cproto = P_ICMP; ih = (struct icmp *)ptop;
1466059Samurai		sport = ih->icmp_type; estab = 1;
1476059Samurai		break;
1486059Samurai	      case IPPROTO_UDP:
1496059Samurai		cproto = P_UDP; uh = (struct udphdr *)ptop;
1506059Samurai		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
1516059Samurai		estab = 1;
1526059Samurai		break;
1536059Samurai	      case IPPROTO_TCP:
1546059Samurai		cproto = P_TCP; th = (struct tcphdr *)ptop;
1556059Samurai		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
1566059Samurai		estab = (th->th_flags & TH_ACK);
1576735Samurai#ifdef DEBUG
1586735Samuraiif (estab == 0)
1596735Samurailogprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
1606735Samurai#endif
1616059Samurai		break;
1626059Samurai	      default:
1636059Samurai		return(A_DENY);	/* We'll block unknown type of packet */
1646059Samurai	      }
1656059Samurai	      gotinfo = 1;
1666059Samurai#ifdef DEBUG
1676059Samurailogprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
1686059Samuraidirection, cproto, fp->opt.srcop, fp->opt.dstop, estab);
1696059Samurai#endif
1706059Samurai	    }
1716059Samurai#ifdef DEBUG
1726059Samurai	    logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n",
1736059Samurai		      n, cproto, sport, dport);
1746059Samurai	    logprintf("check0: action = %d\n", fp->action);
1756059Samurai#endif
1766059Samurai	    if (cproto == fp->proto) {
1776059Samurai	      if ((fp->opt.srcop == OP_NONE ||
1786059Samurai		  PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
1796059Samurai	       &&
1806059Samurai		  (fp->opt.dstop == OP_NONE ||
1816059Samurai		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
1826059Samurai	       &&
1836059Samurai		  (fp->opt.estab == 0 || estab)) {
1846059Samurai		return(fp->action);
1856059Samurai	      }
1866059Samurai	    }
1876059Samurai	  } else {
1886059Samurai	    /* Address is mached. Make a decision. */
1896059Samurai#ifdef DEBUG
1906059Samurai	    logprintf("check1: action = %d\n", fp->action);
1916059Samurai#endif
1926059Samurai	    return(fp->action);
1936059Samurai	  }
1946059Samurai	}
1956059Samurai      }
1966059Samurai      fp++;
1976059Samurai    }
1986059Samuraidrop:
1996059Samurai    return(A_DENY);	/* No rule is mached. Deny this packet */
2006059Samurai  }
2016059Samurai  return(A_PERMIT);	/* No rule is given. Permit this packet */
2026059Samurai}
2036059Samurai
2046059Samuraistatic void
2056059SamuraiIcmpError(pip, code)
2066059Samuraistruct ip *pip;
2076059Samuraiint code;
2086059Samurai{
2096059Samurai#ifdef notdef
2106059Samurai  struct mbuf *bp;
2116059Samurai
2126059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
2136059Samurai    bp = mballoc(cnt, MB_IPIN);
2146059Samurai    bcopy(ptr, MBUF_CTOP(bp), cnt);
2156735Samurai    SendPppFrame(PRI_URGENT, bp);
2166059Samurai    RestartIdleTimer();
2176059Samurai    ipOutOctets += cnt;
2186059Samurai  }
2196059Samurai#endif
2206059Samurai}
2216059Samurai
2226059Samurai/*
2236059Samurai *  For debugging aid.
2246059Samurai */
2256059Samuraiint
2266059SamuraiPacketCheck(cp, nb, direction)
2276059Samuraichar *cp;
2286059Samuraiint nb;
2296059Samuraiint direction;
2306059Samurai{
2316059Samurai  struct ip *pip;
2326059Samurai  struct tcphdr *th;
2336059Samurai  struct udphdr *uh;
2346059Samurai  struct icmp *icmph;
2356059Samurai  char *ptop;
2366059Samurai  int mask, len, n;
2376059Samurai  int logit;
2386059Samurai  int pri = PRI_NORMAL;
2396059Samurai
2406059Samurai  logit = (loglevel & (1 << LOG_TCPIP));
2416059Samurai
2426059Samurai  pip = (struct ip *)cp;
2438857Srgrimes
2446059Samurai  if (logit) logprintf("%s  ", Direction[direction]);
2456059Samurai
2466059Samurai  ptop = (cp + (pip->ip_hl << 2));
2476059Samurai
2486059Samurai  switch (pip->ip_p) {
2496059Samurai  case IPPROTO_ICMP:
2506059Samurai    if (logit) {
2516059Samurai      icmph = (struct icmp *)ptop;
2526059Samurai      logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
2536059Samurai      logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
2546059Samurai    }
2556059Samurai    break;
2566059Samurai  case IPPROTO_UDP:
2576059Samurai    if (logit) {
2586059Samurai      uh = (struct udphdr *)ptop;
2596059Samurai      logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
2606059Samurai      logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
2616059Samurai    }
2626059Samurai    break;
2636059Samurai  case IPPROTO_TCP:
2646059Samurai    th = (struct tcphdr *)ptop;
2656059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
2666059Samurai      pri = PRI_FAST;
2676059Samurai    else if (pip->ip_off == 0) {
2686059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
2696059Samurai	 pri = PRI_FAST;
2706059Samurai    }
2716059Samurai
2726059Samurai    if (logit) {
2736059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
2746059Samurai      logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
2756059Samurai      logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
2766059Samurai      n = 0;
2776059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
2786059Samurai	if (th->th_flags & mask)
2796059Samurai	  logprintf(" %s", TcpFlags[n]);
2806059Samurai	n++;
2816059Samurai      }
2826059Samurai      logprintf("  seq:%x  ack:%x (%d/%d)\n",
2836059Samurai	ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
2846059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
2856059Samurai        u_short *sp;
2866059Samurai
2876059Samurai	ptop += 20;
2886059Samurai	sp = (u_short *)ptop;
2896059Samurai	if (ntohs(sp[0]) == 0x0204)
2906059Samurai	  logprintf(" MSS = %d\n", ntohs(sp[1]));
2916059Samurai      }
2926059Samurai    }
2936059Samurai    break;
2946059Samurai  }
2956059Samurai  pri = FilterCheck(pip, direction);
2966059Samurai  if (pri & A_DENY) {
2976059Samurai#ifdef DEBUG
2986059Samurai    logprintf("blocked.\n");
2996059Samurai#endif
3006059Samurai    if (direction == 0) IcmpError(pip, pri);
3016059Samurai    return(-1);
3026059Samurai  } else {
3037001Samurai    if ( FilterCheck(pip, FL_KEEP ) & A_DENY ) {  /* Check Keep Alive filter */
3046735Samurai	ipKeepAlive = FALSE;
3056735Samurai    } else {
3066735Samurai	ipKeepAlive = TRUE;
3076735Samurai    }
3086059Samurai    return(pri);
3096059Samurai  }
3106059Samurai}
3116059Samurai
3126059Samuraivoid
3136059SamuraiIpInput(bp)
3146059Samuraistruct mbuf *bp;		/* IN: Pointer to IP pakcet */
3156059Samurai{
3166059Samurai  u_char *cp;
3176059Samurai  struct mbuf *wp;
3186059Samurai  int nb, nw;
3196059Samurai  u_char tunbuff[MAX_MRU];
3206059Samurai
3216059Samurai  cp = tunbuff;
3226059Samurai  nb = 0;
3236059Samurai  for (wp = bp; wp; wp = wp->next) {		/* Copy to continuois region */
3246059Samurai    bcopy(MBUF_CTOP(wp), cp, wp->cnt);
3256059Samurai    cp += wp->cnt;
3266059Samurai    nb += wp->cnt;
3276059Samurai  }
3286059Samurai
3297001Samurai  if ( PacketCheck(tunbuff, nb, FL_IN ) < 0) {
3306059Samurai    pfree(bp);
3316059Samurai    return;
3326059Samurai  }
3336059Samurai
3346059Samurai  ipInOctets += nb;
3356059Samurai  /*
3366059Samurai   *  Pass it to tunnel device
3376059Samurai   */
3386059Samurai  nw = write(tun_out, tunbuff, nb);
3396059Samurai  if (nw != nb)
3406059Samurai    fprintf(stderr, "wrote %d, got %d\r\n");
3416059Samurai  pfree(bp);
3426059Samurai
3436059Samurai  RestartIdleTimer();
3446059Samurai}
3456059Samurai
3466059Samuraivoid
3476059SamuraiIpOutput(ptr, cnt)
3486059Samuraiu_char *ptr;			/* IN: Pointer to IP packet */
3496059Samuraiint cnt;			/* IN: Length of packet */
3506059Samurai{
3516059Samurai  struct mbuf *bp;
3526059Samurai  int pri;
3536059Samurai
3546059Samurai  if (IpcpFsm.state != ST_OPENED)
3556059Samurai    return;
3566059Samurai
3577001Samurai  pri = PacketCheck(ptr, cnt, FL_OUT);
3586059Samurai  if (pri >= 0) {
3596059Samurai    bp = mballoc(cnt, MB_IPIN);
3606059Samurai    bcopy(ptr, MBUF_CTOP(bp), cnt);
3616735Samurai    SendPppFrame(pri, bp);
3626059Samurai    RestartIdleTimer();
3636059Samurai    ipOutOctets += cnt;
3646059Samurai  }
3656059Samurai}
3666059Samurai
3676059Samuraistatic struct mqueue IpOutputQueues[PRI_URGENT+1];
3686059Samurai
3696059Samuraivoid
3706059SamuraiIpEnqueue(pri, ptr, count)
3716059Samuraiint pri;
3726059Samuraichar *ptr;
3736059Samuraiint count;
3746059Samurai{
3756059Samurai  struct mbuf *bp;
3766059Samurai
3776059Samurai  bp = mballoc(count, MB_IPQ);
3786059Samurai  bcopy(ptr, MBUF_CTOP(bp), count);
3796059Samurai  Enqueue(&IpOutputQueues[pri], bp);
3806059Samurai}
3816059Samurai
3828857Srgrimesint
3837001SamuraiIsIpEnqueued()
3847001Samurai{
3857001Samurai  struct mqueue *queue;
3867001Samurai  int    exist = FALSE;
3877001Samurai  for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
3887001Samurai     if ( queue->qlen > 0 ) {
3897001Samurai       exist = TRUE;
3907001Samurai       break;
3917001Samurai     }
3927001Samurai  }
3937001Samurai  return( exist );
3947001Samurai}
3957001Samurai
3966059Samuraivoid
3976059SamuraiIpStartOutput()
3986059Samurai{
3996059Samurai  struct mqueue *queue;
4006059Samurai  struct mbuf *bp;
4016059Samurai  int pri, cnt;
4026059Samurai
4036059Samurai  if (IpcpFsm.state != ST_OPENED)
4046059Samurai    return;
4056059Samurai  pri = PRI_URGENT;
4066059Samurai  for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
4076059Samurai    if (queue->top) {
4086059Samurai      bp = Dequeue(queue);
4096059Samurai      if (bp) {
4106059Samurai	cnt = plength(bp);
4116735Samurai	SendPppFrame(pri, bp);
4126059Samurai	RestartIdleTimer();
4136059Samurai	ipOutOctets += cnt;
4146059Samurai       }
4156059Samurai    }
4166059Samurai    pri--;
4176059Samurai  }
4186059Samurai}
419