ip.c revision 26516
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 *
2026516Sbrian * $Id: ip.c,v 1.20 1997/05/26 00:44:01 brian 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>
3413389Sphk#include <arpa/inet.h>
3526031Sbrian#include <alias.h>
3626142Sbrian#include "loadalias.h"
376059Samurai#include "vars.h"
386059Samurai#include "filter.h"
3926516Sbrian#include "mbuf.h"
4026516Sbrian#include "log.h"
416059Samurai
426735Samuraiextern void SendPppFrame();
436059Samuraiextern void LcpClose();
446059Samurai
456059Samuraistatic struct pppTimer IdleTimer;
466059Samurai
476059Samuraistatic void IdleTimeout()
486059Samurai{
4926516Sbrian  LogPrintf(LogPHASE, "Idle timer expired.\n");
5026098Sbrian  reconnect(RECON_FALSE);
516059Samurai  LcpClose();
526059Samurai}
536059Samurai
546059Samurai/*
556059Samurai *  Start Idle timer. If timeout is reached, we call LcpClose() to
566059Samurai *  close LCP and link.
576059Samurai */
586059Samuraivoid
596059SamuraiStartIdleTimer()
606059Samurai{
6120120Snate  if (!(mode & (MODE_DEDICATED|MODE_DDIAL))) {
626059Samurai    StopTimer(&IdleTimer);
636059Samurai    IdleTimer.func = IdleTimeout;
646059Samurai    IdleTimer.load = VarIdleTimeout * SECTICKS;
656059Samurai    IdleTimer.state = TIMER_STOPPED;
666059Samurai    StartTimer(&IdleTimer);
676059Samurai  }
686059Samurai}
696059Samurai
706059Samuraivoid
7126516SbrianUpdateIdleTimer()
7226516Sbrian{
7326516Sbrian  if (IdleTimer.state == TIMER_RUNNING)
7426516Sbrian    StartIdleTimer();
7526516Sbrian}
7626516Sbrian
7726516Sbrianvoid
786059SamuraiStopIdleTimer()
796059Samurai{
806059Samurai  StopTimer(&IdleTimer);
816059Samurai}
826059Samurai
836059Samurai/*
846059Samurai *  If any IP layer traffic is detected, refresh IdleTimer.
856059Samurai */
866059Samuraistatic void
876059SamuraiRestartIdleTimer()
886059Samurai{
8920120Snate  if (!(mode & (MODE_DEDICATED|MODE_DDIAL)) && ipKeepAlive ) {
906059Samurai    StartTimer(&IdleTimer);
916059Samurai    ipIdleSecs = 0;
926059Samurai  }
936059Samurai}
946059Samurai
9513733Sdfrstatic u_short interactive_ports[32] = {
9613733Sdfr  544, 513, 514,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
9713733Sdfr    0,   0,   0,   0,   0,  21,  22,  23,   0,   0,   0,   0,   0,   0,   0, 543,
986059Samurai};
996059Samurai
10013733Sdfr#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
1016059Samurai
1026059Samuraistatic char *TcpFlags[] = {
1036059Samurai  "FIN", "SYN", "RST", "PSH", "ACK", "URG",
1046059Samurai};
1056059Samurai
1066735Samuraistatic char *Direction[] = { "INP", "OUT", "OUT", "IN/OUT" };
1076735Samuraistatic struct filterent *Filters[] = { ifilters, ofilters, dfilters, afilters };
1086059Samurai
1096059Samuraistatic int
1106059SamuraiPortMatch(op, pport, rport)
1116059Samuraiint op;
1126059Samuraiu_short pport, rport;
1136059Samurai{
1146059Samurai  switch (op) {
1156059Samurai  case OP_EQ:
1166059Samurai    return(pport == rport);
1176059Samurai  case OP_GT:
1186059Samurai    return(pport > rport);
1196059Samurai  case OP_LT:
1206059Samurai    return(pport < rport);
1216059Samurai  default:
1226059Samurai    return(0);
1236059Samurai  }
1246059Samurai}
1256059Samurai
1266059Samurai/*
1276059Samurai *  Check a packet against with defined filters
1286059Samurai */
1296059Samuraistatic int
1306059SamuraiFilterCheck(pip, direction)
1316059Samuraistruct ip *pip;
1326059Samuraiint direction;
1336059Samurai{
1346059Samurai  struct filterent *fp = Filters[direction];
1356059Samurai  int gotinfo, cproto, estab, n;
1366059Samurai  struct tcphdr *th;
1376059Samurai  struct udphdr *uh;
1386059Samurai  struct icmp *ih;
1396059Samurai  char *ptop;
1406059Samurai  u_short sport, dport;
1416059Samurai
1426059Samurai  if (fp->action) {
1436059Samurai    cproto = gotinfo = estab = 0;
1446059Samurai    sport = dport = 0;
1456059Samurai    for (n = 0; n < MAXFILTERS; n++) {
1466059Samurai      if (fp->action) {
14710858Samurai         /* permit fragments on in and out filter */
14810858Samurai         if ((direction == FL_IN || direction == FL_OUT) &&
14913733Sdfr             (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
15010858Samurai              return(A_PERMIT);
15110858Samurai         }
15226516Sbrian        LogPrintf(LogDEBUG, "rule = %d\n", n);
1536059Samurai	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
1546059Samurai	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
1556059Samurai	  if (fp->proto) {
1566059Samurai	    if (!gotinfo) {
1576059Samurai	      ptop = (char *)pip + (pip->ip_hl << 2);
1586059Samurai
1596059Samurai	      switch (pip->ip_p) {
1606059Samurai	      case IPPROTO_ICMP:
1616059Samurai		cproto = P_ICMP; ih = (struct icmp *)ptop;
1626059Samurai		sport = ih->icmp_type; estab = 1;
1636059Samurai		break;
1646059Samurai	      case IPPROTO_UDP:
1656059Samurai		cproto = P_UDP; uh = (struct udphdr *)ptop;
1666059Samurai		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
1676059Samurai		estab = 1;
1686059Samurai		break;
1696059Samurai	      case IPPROTO_TCP:
1706059Samurai		cproto = P_TCP; th = (struct tcphdr *)ptop;
1716059Samurai		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
1726059Samurai		estab = (th->th_flags & TH_ACK);
17326516Sbrian                if (estab == 0)
17426516Sbrian                  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
17526516Sbrian                            th->th_flags, sport, dport);
1766059Samurai		break;
1776059Samurai	      default:
1786059Samurai		return(A_DENY);	/* We'll block unknown type of packet */
1796059Samurai	      }
1806059Samurai	      gotinfo = 1;
18126516Sbrian              LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
18226516Sbrian                       " dstop = %d, estab = %d\n", direction, cproto,
18326516Sbrian                       fp->opt.srcop, fp->opt.dstop, estab);
1846059Samurai	    }
18526516Sbrian
18626516Sbrian	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
18726516Sbrian                      " dport = %d\n", n, cproto, sport, dport);
18826516Sbrian	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
18926516Sbrian
1906059Samurai	    if (cproto == fp->proto) {
1916059Samurai	      if ((fp->opt.srcop == OP_NONE ||
1926059Samurai		  PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
1936059Samurai	       &&
1946059Samurai		  (fp->opt.dstop == OP_NONE ||
1956059Samurai		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
1966059Samurai	       &&
1976059Samurai		  (fp->opt.estab == 0 || estab)) {
1986059Samurai		return(fp->action);
1996059Samurai	      }
2006059Samurai	    }
2016059Samurai	  } else {
2026059Samurai	    /* Address is mached. Make a decision. */
20326516Sbrian	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
2046059Samurai	    return(fp->action);
2056059Samurai	  }
2066059Samurai	}
2076059Samurai      }
2086059Samurai      fp++;
2096059Samurai    }
2106059Samurai    return(A_DENY);	/* No rule is mached. Deny this packet */
2116059Samurai  }
2126059Samurai  return(A_PERMIT);	/* No rule is given. Permit this packet */
2136059Samurai}
2146059Samurai
2156059Samuraistatic void
2166059SamuraiIcmpError(pip, code)
2176059Samuraistruct ip *pip;
2186059Samuraiint code;
2196059Samurai{
2206059Samurai#ifdef notdef
2216059Samurai  struct mbuf *bp;
2226059Samurai
2236059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
2246059Samurai    bp = mballoc(cnt, MB_IPIN);
2256059Samurai    bcopy(ptr, MBUF_CTOP(bp), cnt);
22613733Sdfr    SendPppFrame(bp);
2276059Samurai    RestartIdleTimer();
2286059Samurai    ipOutOctets += cnt;
2296059Samurai  }
2306059Samurai#endif
2316059Samurai}
2326059Samurai
2336059Samurai/*
2346059Samurai *  For debugging aid.
2356059Samurai */
2366059Samuraiint
2376059SamuraiPacketCheck(cp, nb, direction)
2386059Samuraichar *cp;
2396059Samuraiint nb;
2406059Samuraiint direction;
2416059Samurai{
2426059Samurai  struct ip *pip;
2436059Samurai  struct tcphdr *th;
2446059Samurai  struct udphdr *uh;
2456059Samurai  struct icmp *icmph;
2466059Samurai  char *ptop;
2476059Samurai  int mask, len, n;
2486059Samurai  int logit;
2496059Samurai  int pri = PRI_NORMAL;
2506059Samurai
25126516Sbrian  logit = LogIsKept(LogTCPIP);
2526059Samurai
2536059Samurai  pip = (struct ip *)cp;
2548857Srgrimes
25526516Sbrian  if (logit) LogPrintf(LogTCPIP, "%s  ", Direction[direction]);
2566059Samurai
2576059Samurai  ptop = (cp + (pip->ip_hl << 2));
2586059Samurai
2596059Samurai  switch (pip->ip_p) {
2606059Samurai  case IPPROTO_ICMP:
2616059Samurai    if (logit) {
2626059Samurai      icmph = (struct icmp *)ptop;
26326516Sbrian      LogPrintf(LogTCPIP, "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
26426516Sbrian      LogPrintf(LogTCPIP, "%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
2656059Samurai    }
2666059Samurai    break;
2676059Samurai  case IPPROTO_UDP:
2686059Samurai    if (logit) {
2696059Samurai      uh = (struct udphdr *)ptop;
27026516Sbrian      LogPrintf(LogTCPIP, "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
27126516Sbrian      LogPrintf(LogTCPIP, "%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
2726059Samurai    }
2736059Samurai    break;
2746059Samurai  case IPPROTO_TCP:
2756059Samurai    th = (struct tcphdr *)ptop;
2766059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
2776059Samurai      pri = PRI_FAST;
27813733Sdfr    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
2796059Samurai      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
2806059Samurai	 pri = PRI_FAST;
2816059Samurai    }
2826059Samurai
2836059Samurai    if (logit) {
2846059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
28526516Sbrian      LogPrintf(LogTCPIP, "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
28626516Sbrian      LogPrintf(LogTCPIP, "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
2876059Samurai      n = 0;
2886059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
2896059Samurai	if (th->th_flags & mask)
29026516Sbrian	  LogPrintf(LogTCPIP, " %s", TcpFlags[n]);
2916059Samurai	n++;
2926059Samurai      }
29326516Sbrian      LogPrintf(LogTCPIP, "  seq:%x  ack:%x (%d/%d)\n",
2946059Samurai	ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
2956059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
2966059Samurai        u_short *sp;
2976059Samurai
2986059Samurai	ptop += 20;
2996059Samurai	sp = (u_short *)ptop;
3006059Samurai	if (ntohs(sp[0]) == 0x0204)
30126516Sbrian	  LogPrintf(LogTCPIP, " MSS = %d\n", ntohs(sp[1]));
3026059Samurai      }
3036059Samurai    }
3046059Samurai    break;
3056059Samurai  }
30613733Sdfr
30713733Sdfr  if ((FilterCheck(pip, direction) & A_DENY)) {
30826516Sbrian    LogPrintf(LogDEBUG, "blocked.\n");
3096059Samurai    if (direction == 0) IcmpError(pip, pri);
3106059Samurai    return(-1);
3116059Samurai  } else {
3127001Samurai    if ( FilterCheck(pip, FL_KEEP ) & A_DENY ) {  /* Check Keep Alive filter */
3136735Samurai	ipKeepAlive = FALSE;
3146735Samurai    } else {
3156735Samurai	ipKeepAlive = TRUE;
3166735Samurai    }
3176059Samurai    return(pri);
3186059Samurai  }
3196059Samurai}
3206059Samurai
3216059Samuraivoid
3226059SamuraiIpInput(bp)
3236059Samuraistruct mbuf *bp;		/* IN: Pointer to IP pakcet */
3246059Samurai{
3256059Samurai  u_char *cp;
3266059Samurai  struct mbuf *wp;
3276059Samurai  int nb, nw;
3286059Samurai  u_char tunbuff[MAX_MRU];
3296059Samurai
3306059Samurai  cp = tunbuff;
3316059Samurai  nb = 0;
33226516Sbrian  for (wp = bp; wp; wp = wp->next) {		/* Copy to contiguous region */
3336059Samurai    bcopy(MBUF_CTOP(wp), cp, wp->cnt);
3346059Samurai    cp += wp->cnt;
3356059Samurai    nb += wp->cnt;
3366059Samurai  }
3376059Samurai
33820365Sjkh  if (mode & MODE_ALIAS) {
33926031Sbrian    int iresult;
34026031Sbrian    char *fptr;
34126031Sbrian
34226142Sbrian    iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff);
34326031Sbrian    nb = ntohs(((struct ip *) tunbuff)->ip_len);
34426031Sbrian
34526031Sbrian    if (nb > MAX_MRU) {
34626516Sbrian      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
34726031Sbrian      pfree(bp);
34826031Sbrian      return;
34926031Sbrian    }
35026031Sbrian
35126031Sbrian    if (iresult == PKT_ALIAS_OK
35226031Sbrian     || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
35326031Sbrian      if ( PacketCheck(tunbuff, nb, FL_IN ) < 0) {
35426031Sbrian          pfree(bp);
35526031Sbrian          return;
35626031Sbrian      }
35726031Sbrian
35826031Sbrian      ipInOctets += nb;
35926031Sbrian
36026031Sbrian      nb = ntohs(((struct ip *) tunbuff)->ip_len);
36126031Sbrian      nw = write(tun_out, tunbuff, nb);
36226031Sbrian      if (nw != nb)
36326516Sbrian        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
36426031Sbrian
36526031Sbrian      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
36626142Sbrian        while ((fptr = VarGetNextFragmentPtr(tunbuff)) != NULL) {
36726142Sbrian          VarFragmentAliasIn(tunbuff, fptr);
36826031Sbrian          nb = ntohs(((struct ip *) fptr)->ip_len);
36926031Sbrian          nw = write(tun_out, fptr, nb);
37026031Sbrian          if (nw != nb)
37126516Sbrian            LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
37226031Sbrian          free(fptr);
37326031Sbrian        }
37426031Sbrian      }
37526031Sbrian    }
37626031Sbrian    else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
37726031Sbrian      nb = ntohs(((struct ip *) tunbuff)->ip_len);
37826031Sbrian      fptr = malloc(nb);
37926516Sbrian      if (fptr == NULL)
38026516Sbrian        LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
38126031Sbrian      else {
38226031Sbrian        memcpy(fptr, tunbuff, nb);
38326142Sbrian        VarSaveFragmentPtr(fptr);
38426031Sbrian      }
38526031Sbrian    }
38620365Sjkh  }
38726031Sbrian  else
38826031Sbrian  { /* no aliasing */
38926031Sbrian    if ( PacketCheck(tunbuff, nb, FL_IN ) < 0)
39026031Sbrian    {
39126031Sbrian      pfree(bp);
39226031Sbrian      return;
39326031Sbrian    }
39420365Sjkh
39526031Sbrian    ipInOctets += nb;
39626031Sbrian    nw = write(tun_out, tunbuff, nb);
39726031Sbrian    if (nw != nb)
39826516Sbrian      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
3996059Samurai  }
4006059Samurai  pfree(bp);
4016059Samurai
4026059Samurai  RestartIdleTimer();
4036059Samurai}
4046059Samurai
40513733Sdfrstatic struct mqueue IpOutputQueues[PRI_FAST+1];
4066059Samurai
4076059Samuraivoid
4086059SamuraiIpEnqueue(pri, ptr, count)
4096059Samuraiint pri;
4106059Samuraichar *ptr;
4116059Samuraiint count;
4126059Samurai{
4136059Samurai  struct mbuf *bp;
4146059Samurai
4156059Samurai  bp = mballoc(count, MB_IPQ);
4166059Samurai  bcopy(ptr, MBUF_CTOP(bp), count);
4176059Samurai  Enqueue(&IpOutputQueues[pri], bp);
4186059Samurai}
4196059Samurai
4208857Srgrimesint
4217001SamuraiIsIpEnqueued()
4227001Samurai{
4237001Samurai  struct mqueue *queue;
4247001Samurai  int    exist = FALSE;
42513733Sdfr  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
4267001Samurai     if ( queue->qlen > 0 ) {
4277001Samurai       exist = TRUE;
4287001Samurai       break;
4297001Samurai     }
4307001Samurai  }
4317001Samurai  return( exist );
4327001Samurai}
4337001Samurai
4346059Samuraivoid
4356059SamuraiIpStartOutput()
4366059Samurai{
4376059Samurai  struct mqueue *queue;
4386059Samurai  struct mbuf *bp;
43925630Sbrian  int cnt;
4406059Samurai
4416059Samurai  if (IpcpFsm.state != ST_OPENED)
4426059Samurai    return;
44313733Sdfr  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
4446059Samurai    if (queue->top) {
4456059Samurai      bp = Dequeue(queue);
4466059Samurai      if (bp) {
4476059Samurai	cnt = plength(bp);
44813733Sdfr	SendPppFrame(bp);
4496059Samurai	RestartIdleTimer();
4506059Samurai	ipOutOctets += cnt;
45113733Sdfr	break;
4526059Samurai       }
4536059Samurai    }
4546059Samurai  }
4556059Samurai}
456