ip.c revision 6059
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.
196059Samurai *
206059Samurai * $Id:$
216059Samurai *
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
376059Samuraiextern void SendPppFlame();
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{
776059Samurai  if (!(mode & MODE_DEDICATED)) {
786059Samurai    StopTimer(&IdleTimer);
796059Samurai    StartTimer(&IdleTimer);
806059Samurai    ipIdleSecs = 0;
816059Samurai  }
826059Samurai}
836059Samurai
846059Samuraistatic u_short interactive_ports[8] = {
856059Samurai  0, 513, 0, 0, 0, 21, 0, 23,
866059Samurai};
876059Samurai
886059Samurai#define	INTERACTIVE(p)	(interactive_ports[(p) & 7] == (p))
896059Samurai
906059Samuraistatic char *TcpFlags[] = {
916059Samurai  "FIN", "SYN", "RST", "PSH", "ACK", "URG",
926059Samurai};
936059Samurai
946059Samuraistatic char *Direction[] = { "INP", "OUT", "OUT" };
956059Samuraistatic struct filterent *Filters[] = { ifilters, ofilters, dfilters };
966059Samurai
976059Samuraistatic int
986059SamuraiPortMatch(op, pport, rport)
996059Samuraiint op;
1006059Samuraiu_short pport, rport;
1016059Samurai{
1026059Samurai  switch (op) {
1036059Samurai  case OP_EQ:
1046059Samurai    return(pport == rport);
1056059Samurai  case OP_GT:
1066059Samurai    return(pport > rport);
1076059Samurai  case OP_LT:
1086059Samurai    return(pport < rport);
1096059Samurai  default:
1106059Samurai    return(0);
1116059Samurai  }
1126059Samurai}
1136059Samurai
1146059Samurai/*
1156059Samurai *  Check a packet against with defined filters
1166059Samurai */
1176059Samuraistatic int
1186059SamuraiFilterCheck(pip, direction)
1196059Samuraistruct ip *pip;
1206059Samuraiint direction;
1216059Samurai{
1226059Samurai  struct filterent *fp = Filters[direction];
1236059Samurai  int gotinfo, cproto, estab, n;
1246059Samurai  struct tcphdr *th;
1256059Samurai  struct udphdr *uh;
1266059Samurai  struct icmp *ih;
1276059Samurai  char *ptop;
1286059Samurai  u_short sport, dport;
1296059Samurai
1306059Samurai  if (fp->action) {
1316059Samurai    cproto = gotinfo = estab = 0;
1326059Samurai    sport = dport = 0;
1336059Samurai    for (n = 0; n < MAXFILTERS; n++) {
1346059Samurai      if (fp->action) {
1356059Samurai#ifdef DEBUG
1366059Samurailogprintf("rule = %d\n", n);
1376059Samurai#endif
1386059Samurai	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
1396059Samurai	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
1406059Samurai	  if (fp->proto) {
1416059Samurai	    if (!gotinfo) {
1426059Samurai	      ptop = (char *)pip + (pip->ip_hl << 2);
1436059Samurai
1446059Samurai	      switch (pip->ip_p) {
1456059Samurai	      case IPPROTO_ICMP:
1466059Samurai		cproto = P_ICMP; ih = (struct icmp *)ptop;
1476059Samurai		sport = ih->icmp_type; estab = 1;
1486059Samurai		break;
1496059Samurai	      case IPPROTO_UDP:
1506059Samurai		cproto = P_UDP; uh = (struct udphdr *)ptop;
1516059Samurai		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
1526059Samurai		estab = 1;
1536059Samurai		break;
1546059Samurai	      case IPPROTO_TCP:
1556059Samurai		cproto = P_TCP; th = (struct tcphdr *)ptop;
1566059Samurai		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
1576059Samurai		estab = (th->th_flags & TH_ACK);
1586059Samurai		break;
1596059Samurai	      default:
1606059Samurai		return(A_DENY);	/* We'll block unknown type of packet */
1616059Samurai	      }
1626059Samurai	      gotinfo = 1;
1636059Samurai#ifdef DEBUG
1646059Samurailogprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
1656059Samuraidirection, cproto, fp->opt.srcop, fp->opt.dstop, estab);
1666059Samuraiif (estab == 0)
1676059Samurailogprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
1686059Samurai#endif
1696059Samurai	    }
1706059Samurai#ifdef DEBUG
1716059Samurai	    logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n",
1726059Samurai		      n, cproto, sport, dport);
1736059Samurai	    logprintf("check0: action = %d\n", fp->action);
1746059Samurai#endif
1756059Samurai	    if (cproto == fp->proto) {
1766059Samurai	      if ((fp->opt.srcop == OP_NONE ||
1776059Samurai		  PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
1786059Samurai	       &&
1796059Samurai		  (fp->opt.dstop == OP_NONE ||
1806059Samurai		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
1816059Samurai	       &&
1826059Samurai		  (fp->opt.estab == 0 || estab)) {
1836059Samurai		return(fp->action);
1846059Samurai	      }
1856059Samurai	    }
1866059Samurai	  } else {
1876059Samurai	    /* Address is mached. Make a decision. */
1886059Samurai#ifdef DEBUG
1896059Samurai	    logprintf("check1: action = %d\n", fp->action);
1906059Samurai#endif
1916059Samurai	    return(fp->action);
1926059Samurai	  }
1936059Samurai	}
1946059Samurai      }
1956059Samurai      fp++;
1966059Samurai    }
1976059Samuraidrop:
1986059Samurai    return(A_DENY);	/* No rule is mached. Deny this packet */
1996059Samurai  }
2006059Samurai  return(A_PERMIT);	/* No rule is given. Permit this packet */
2016059Samurai}
2026059Samurai
2036059Samuraistatic void
2046059SamuraiIcmpError(pip, code)
2056059Samuraistruct ip *pip;
2066059Samuraiint code;
2076059Samurai{
2086059Samurai#ifdef notdef
2096059Samurai  struct mbuf *bp;
2106059Samurai
2116059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
2126059Samurai    bp = mballoc(cnt, MB_IPIN);
2136059Samurai    bcopy(ptr, MBUF_CTOP(bp), cnt);
2146059Samurai    SendPppFlame(PRI_URGENT, bp);
2156059Samurai    RestartIdleTimer();
2166059Samurai    ipOutOctets += cnt;
2176059Samurai  }
2186059Samurai#endif
2196059Samurai}
2206059Samurai
2216059Samurai/*
2226059Samurai *  For debugging aid.
2236059Samurai */
2246059Samuraiint
2256059SamuraiPacketCheck(cp, nb, direction)
2266059Samuraichar *cp;
2276059Samuraiint nb;
2286059Samuraiint direction;
2296059Samurai{
2306059Samurai  struct ip *pip;
2316059Samurai  struct tcphdr *th;
2326059Samurai  struct udphdr *uh;
2336059Samurai  struct icmp *icmph;
2346059Samurai  char *ptop;
2356059Samurai  int mask, len, n;
2366059Samurai  int logit;
2376059Samurai  int pri = PRI_NORMAL;
2386059Samurai
2396059Samurai  logit = (loglevel & (1 << LOG_TCPIP));
2406059Samurai
2416059Samurai  pip = (struct ip *)cp;
2426059Samurai
2436059Samurai  if (logit) logprintf("%s  ", Direction[direction]);
2446059Samurai
2456059Samurai  ptop = (cp + (pip->ip_hl << 2));
2466059Samurai
2476059Samurai  switch (pip->ip_p) {
2486059Samurai  case IPPROTO_ICMP:
2496059Samurai    if (logit) {
2506059Samurai      icmph = (struct icmp *)ptop;
2516059Samurai      logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
2526059Samurai      logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
2536059Samurai    }
2546059Samurai    break;
2556059Samurai  case IPPROTO_UDP:
2566059Samurai    if (logit) {
2576059Samurai      uh = (struct udphdr *)ptop;
2586059Samurai      logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
2596059Samurai      logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
2606059Samurai    }
2616059Samurai    break;
2626059Samurai  case IPPROTO_TCP:
2636059Samurai    th = (struct tcphdr *)ptop;
2646059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
2656059Samurai      pri = PRI_FAST;
2666059Samurai    else if (pip->ip_off == 0) {
2676059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
2686059Samurai	 pri = PRI_FAST;
2696059Samurai    }
2706059Samurai
2716059Samurai    if (logit) {
2726059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
2736059Samurai      logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
2746059Samurai      logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
2756059Samurai      n = 0;
2766059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
2776059Samurai	if (th->th_flags & mask)
2786059Samurai	  logprintf(" %s", TcpFlags[n]);
2796059Samurai	n++;
2806059Samurai      }
2816059Samurai      logprintf("  seq:%x  ack:%x (%d/%d)\n",
2826059Samurai	ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
2836059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
2846059Samurai        u_short *sp;
2856059Samurai
2866059Samurai	ptop += 20;
2876059Samurai	sp = (u_short *)ptop;
2886059Samurai	if (ntohs(sp[0]) == 0x0204)
2896059Samurai	  logprintf(" MSS = %d\n", ntohs(sp[1]));
2906059Samurai      }
2916059Samurai    }
2926059Samurai    break;
2936059Samurai  }
2946059Samurai  pri = FilterCheck(pip, direction);
2956059Samurai  if (pri & A_DENY) {
2966059Samurai#ifdef DEBUG
2976059Samurai    logprintf("blocked.\n");
2986059Samurai#endif
2996059Samurai    if (direction == 0) IcmpError(pip, pri);
3006059Samurai    return(-1);
3016059Samurai  } else {
3026059Samurai    return(pri);
3036059Samurai  }
3046059Samurai}
3056059Samurai
3066059Samuraivoid
3076059SamuraiIpInput(bp)
3086059Samuraistruct mbuf *bp;		/* IN: Pointer to IP pakcet */
3096059Samurai{
3106059Samurai  u_char *cp;
3116059Samurai  struct mbuf *wp;
3126059Samurai  int nb, nw;
3136059Samurai  u_char tunbuff[MAX_MRU];
3146059Samurai
3156059Samurai  cp = tunbuff;
3166059Samurai  nb = 0;
3176059Samurai  for (wp = bp; wp; wp = wp->next) {		/* Copy to continuois region */
3186059Samurai    bcopy(MBUF_CTOP(wp), cp, wp->cnt);
3196059Samurai    cp += wp->cnt;
3206059Samurai    nb += wp->cnt;
3216059Samurai  }
3226059Samurai
3236059Samurai  if (PacketCheck(tunbuff, nb, 0) < 0) {
3246059Samurai    pfree(bp);
3256059Samurai    return;
3266059Samurai  }
3276059Samurai
3286059Samurai  ipInOctets += nb;
3296059Samurai  /*
3306059Samurai   *  Pass it to tunnel device
3316059Samurai   */
3326059Samurai  nw = write(tun_out, tunbuff, nb);
3336059Samurai  if (nw != nb)
3346059Samurai    fprintf(stderr, "wrote %d, got %d\r\n");
3356059Samurai  pfree(bp);
3366059Samurai
3376059Samurai  RestartIdleTimer();
3386059Samurai}
3396059Samurai
3406059Samuraivoid
3416059SamuraiIpOutput(ptr, cnt)
3426059Samuraiu_char *ptr;			/* IN: Pointer to IP packet */
3436059Samuraiint cnt;			/* IN: Length of packet */
3446059Samurai{
3456059Samurai  struct mbuf *bp;
3466059Samurai  int pri;
3476059Samurai
3486059Samurai  if (IpcpFsm.state != ST_OPENED)
3496059Samurai    return;
3506059Samurai
3516059Samurai  pri = PacketCheck(ptr, cnt, 1);
3526059Samurai  if (pri >= 0) {
3536059Samurai    bp = mballoc(cnt, MB_IPIN);
3546059Samurai    bcopy(ptr, MBUF_CTOP(bp), cnt);
3556059Samurai    SendPppFlame(pri, bp);
3566059Samurai    RestartIdleTimer();
3576059Samurai    ipOutOctets += cnt;
3586059Samurai  }
3596059Samurai}
3606059Samurai
3616059Samuraistatic struct mqueue IpOutputQueues[PRI_URGENT+1];
3626059Samurai
3636059Samuraivoid
3646059SamuraiIpEnqueue(pri, ptr, count)
3656059Samuraiint pri;
3666059Samuraichar *ptr;
3676059Samuraiint count;
3686059Samurai{
3696059Samurai  struct mbuf *bp;
3706059Samurai
3716059Samurai  bp = mballoc(count, MB_IPQ);
3726059Samurai  bcopy(ptr, MBUF_CTOP(bp), count);
3736059Samurai  Enqueue(&IpOutputQueues[pri], bp);
3746059Samurai}
3756059Samurai
3766059Samuraivoid
3776059SamuraiIpStartOutput()
3786059Samurai{
3796059Samurai  struct mqueue *queue;
3806059Samurai  struct mbuf *bp;
3816059Samurai  int pri, cnt;
3826059Samurai
3836059Samurai  if (IpcpFsm.state != ST_OPENED)
3846059Samurai    return;
3856059Samurai  pri = PRI_URGENT;
3866059Samurai  for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
3876059Samurai    if (queue->top) {
3886059Samurai      bp = Dequeue(queue);
3896059Samurai      if (bp) {
3906059Samurai	cnt = plength(bp);
3916059Samurai	SendPppFlame(pri, bp);
3926059Samurai	RestartIdleTimer();
3936059Samurai	ipOutOctets += cnt;
3946059Samurai       }
3956059Samurai    }
3966059Samurai    pri--;
3976059Samurai  }
3986059Samurai}
399