ip.c revision 65181
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 *
2050479Speter * $FreeBSD: head/usr.sbin/ppp/ip.c 65181 2000-08-28 23:24:52Z brian $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Return ICMP message for filterd packet
246059Samurai *		  and optionaly record it into log.
256059Samurai */
2643313Sbrian#include <sys/param.h>
2731195Sbrian#include <sys/socket.h>
2830715Sbrian#include <netinet/in.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>
3536285Sbrian#include <sys/un.h>
3630715Sbrian
3730092Sbrian#include <errno.h>
3830715Sbrian#include <stdio.h>
3930715Sbrian#include <string.h>
4046686Sbrian#include <termios.h>
4130715Sbrian#include <unistd.h>
4230715Sbrian
4346686Sbrian#include "layer.h"
4446686Sbrian#include "proto.h"
4530715Sbrian#include "mbuf.h"
4630715Sbrian#include "log.h"
4730715Sbrian#include "defs.h"
4830715Sbrian#include "timer.h"
4930715Sbrian#include "fsm.h"
5036285Sbrian#include "lqr.h"
5130715Sbrian#include "hdlc.h"
5236285Sbrian#include "throughput.h"
5336285Sbrian#include "iplist.h"
5436285Sbrian#include "slcompress.h"
5536285Sbrian#include "ipcp.h"
566059Samurai#include "filter.h"
5736285Sbrian#include "descriptor.h"
5836285Sbrian#include "lcp.h"
5936285Sbrian#include "ccp.h"
6036285Sbrian#include "link.h"
6136285Sbrian#include "mp.h"
6243313Sbrian#ifndef NORADIUS
6343313Sbrian#include "radius.h"
6443313Sbrian#endif
6536285Sbrian#include "bundle.h"
6631195Sbrian#include "tun.h"
6730715Sbrian#include "ip.h"
686059Samurai
6958033Sbrian
7058033Sbrian#define OPCODE_QUERY	0
7158033Sbrian#define OPCODE_IQUERY	1
7258033Sbrian#define OPCODE_STATUS	2
7358033Sbrian
7458033Sbrianstruct dns_header {
7558033Sbrian  u_short id;
7658033Sbrian  unsigned qr : 1;
7758033Sbrian  unsigned opcode : 4;
7858033Sbrian  unsigned aa : 1;
7958033Sbrian  unsigned tc : 1;
8058033Sbrian  unsigned rd : 1;
8158033Sbrian  unsigned ra : 1;
8258033Sbrian  unsigned z : 3;
8358033Sbrian  unsigned rcode : 4;
8458033Sbrian  u_short qdcount;
8558033Sbrian  u_short ancount;
8658033Sbrian  u_short nscount;
8758033Sbrian  u_short arcount;
8855146Sbrian};
896059Samurai
9058033Sbrianstatic const char *
9158033Sbriandns_Qclass2Txt(u_short qclass)
9258033Sbrian{
9358033Sbrian  static char failure[6];
9458033Sbrian  struct {
9558033Sbrian    u_short id;
9658033Sbrian    const char *txt;
9758033Sbrian  } qtxt[] = {
9858033Sbrian    /* rfc1035 */
9958033Sbrian    { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
10058033Sbrian  };
10158033Sbrian  int f;
10258033Sbrian
10358033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
10458033Sbrian    if (qtxt[f].id == qclass)
10558033Sbrian      return qtxt[f].txt;
10658033Sbrian
10758034Sbrian  return HexStr(qclass, failure, sizeof failure);
10858033Sbrian}
10958033Sbrian
11058033Sbrianstatic const char *
11158033Sbriandns_Qtype2Txt(u_short qtype)
11258033Sbrian{
11358033Sbrian  static char failure[6];
11458033Sbrian  struct {
11558033Sbrian    u_short id;
11658033Sbrian    const char *txt;
11758033Sbrian  } qtxt[] = {
11858033Sbrian    /* rfc1035/rfc1700 */
11958033Sbrian    { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
12058033Sbrian    { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
12158033Sbrian    { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
12258033Sbrian    { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
12358033Sbrian    { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
12458033Sbrian    { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
12558033Sbrian    { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
12658033Sbrian    { 254, "MAILA" }, { 255, "*" }
12758033Sbrian  };
12858033Sbrian  int f;
12958033Sbrian
13058033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
13158033Sbrian    if (qtxt[f].id == qtype)
13258033Sbrian      return qtxt[f].txt;
13358033Sbrian
13458034Sbrian  return HexStr(qtype, failure, sizeof failure);
13558033Sbrian}
13658033Sbrian
13749140Sbrianstatic __inline int
13828679SbrianPortMatch(int op, u_short pport, u_short rport)
1396059Samurai{
1406059Samurai  switch (op) {
14149140Sbrian  case OP_EQ:
14262977Sbrian    return pport == rport;
1436059Samurai  case OP_GT:
14462977Sbrian    return pport > rport;
1456059Samurai  case OP_LT:
14662977Sbrian    return pport < rport;
1476059Samurai  default:
14862977Sbrian    return 0;
1496059Samurai  }
1506059Samurai}
1516059Samurai
1526059Samurai/*
15346686Sbrian *  Check a packet against a defined filter
15449140Sbrian *  Returns 0 to accept the packet, non-zero to drop the packet
15549140Sbrian *
15649140Sbrian *  If filtering is enabled, the initial fragment of a datagram must
15749140Sbrian *  contain the complete protocol header, and subsequent fragments
15849140Sbrian *  must not attempt to over-write it.
1596059Samurai */
1606059Samuraistatic int
16162977SbrianFilterCheck(const struct ip *pip, const struct filter *filter, unsigned *psecs)
1626059Samurai{
16349140Sbrian  int gotinfo;			/* true if IP payload decoded */
16449140Sbrian  int cproto;			/* P_* protocol type if (gotinfo) */
16549140Sbrian  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
16649140Sbrian  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
16749140Sbrian  int n;			/* filter rule to process */
16849140Sbrian  int len;			/* bytes used in dbuff */
16949140Sbrian  int didname;			/* true if filter header printed */
17049140Sbrian  int match;			/* true if condition matched */
17149140Sbrian  const struct filterent *fp = filter->rule;
17265181Sbrian  char dbuff[100], dstip[16];
1736059Samurai
17449140Sbrian  if (fp->f_action == A_NONE)
17562977Sbrian    return 0;		/* No rule is given. Permit this packet */
17636285Sbrian
17762977Sbrian  /*
17862977Sbrian   * Deny any packet fragment that tries to over-write the header.
17949140Sbrian   * Since we no longer have the real header available, punt on the
18049140Sbrian   * largest normal header - 20 bytes for TCP without options, rounded
18149140Sbrian   * up to the next possible fragment boundary.  Since the smallest
18249140Sbrian   * `legal' MTU is 576, and the smallest recommended MTU is 296, any
18362977Sbrian   * fragmentation within this range is dubious at best
18462977Sbrian   */
18549140Sbrian  len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
18649140Sbrian  if (len > 0) {		/* Not first fragment within datagram */
18765181Sbrian    if (len < (24 >> 3)) {	/* don't allow fragment to over-write header */
18865181Sbrian      log_Printf(LogFILTER, " error: illegal header\n");
18962977Sbrian      return 1;
19065181Sbrian    }
19149140Sbrian    /* permit fragments on in and out filter */
19265181Sbrian    if (!filter->fragok) {
19365181Sbrian      log_Printf(LogFILTER, " error: illegal fragmentation\n");
19465181Sbrian      return 1;
19565181Sbrian    } else
19665181Sbrian      return 0;
19749140Sbrian  }
19849140Sbrian
19949140Sbrian  cproto = gotinfo = estab = syn = finrst = didname = 0;
20049140Sbrian  sport = dport = 0;
20149140Sbrian  for (n = 0; n < MAXFILTERS; ) {
20249140Sbrian    if (fp->f_action == A_NONE) {
20349140Sbrian      n++;
20449140Sbrian      fp++;
20549140Sbrian      continue;
20649140Sbrian    }
20736285Sbrian
20849140Sbrian    if (!didname) {
20949140Sbrian      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
21049140Sbrian      didname = 1;
21149140Sbrian    }
2126059Samurai
21349140Sbrian    match = 0;
21449140Sbrian    if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
21562977Sbrian          fp->f_src.mask.s_addr) &&
21662977Sbrian        !((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
21762977Sbrian          fp->f_dst.mask.s_addr)) {
21849140Sbrian      if (fp->f_proto != P_NONE) {
21962977Sbrian        if (!gotinfo) {
22062977Sbrian          const char *ptop = (const char *) pip + (pip->ip_hl << 2);
22162977Sbrian          const struct tcphdr *th;
22262977Sbrian          const struct udphdr *uh;
22362977Sbrian          const struct icmp *ih;
22462977Sbrian          int datalen;	/* IP datagram length */
22549140Sbrian
22662977Sbrian          datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
22762977Sbrian          switch (pip->ip_p) {
22862977Sbrian          case IPPROTO_ICMP:
22962977Sbrian            cproto = P_ICMP;
23065181Sbrian            if (datalen < 8) {	/* ICMP must be at least 8 octets */
23165181Sbrian              log_Printf(LogFILTER, " error: ICMP must be at least 8 octets\n");
23262977Sbrian              return 1;
23365181Sbrian            }
23465181Sbrian
23562977Sbrian            ih = (const struct icmp *) ptop;
23662977Sbrian            sport = ih->icmp_type;
23762977Sbrian            estab = syn = finrst = -1;
23862977Sbrian            if (log_IsKept(LogDEBUG))
23962977Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
24062977Sbrian            break;
24162977Sbrian          case IPPROTO_IGMP:
24262977Sbrian            cproto = P_IGMP;
24365181Sbrian            if (datalen < 8) {	/* IGMP uses 8-octet messages */
24465181Sbrian              log_Printf(LogFILTER, " error: IGMP must be at least 8 octets\n");
24562977Sbrian              return 1;
24665181Sbrian            }
24762977Sbrian            estab = syn = finrst = -1;
24862977Sbrian            sport = ntohs(0);
24962977Sbrian            break;
25051809Sbrian#ifdef IPPROTO_GRE
25151809Sbrian          case IPPROTO_GRE:
25251809Sbrian            cproto = P_GRE;
25365181Sbrian            if (datalen < 2) {    /* GRE uses 2-octet+ messages */
25465181Sbrian              log_Printf(LogFILTER, " error: GRE must be at least 2 octets\n");
25562977Sbrian              return 1;
25665181Sbrian            }
25751809Sbrian            estab = syn = finrst = -1;
25851809Sbrian            sport = ntohs(0);
25951809Sbrian            break;
26051809Sbrian#endif
26149374Sbrian#ifdef IPPROTO_OSPFIGP
26262977Sbrian          case IPPROTO_OSPFIGP:
26362977Sbrian            cproto = P_OSPF;
26465181Sbrian            if (datalen < 8) {	/* IGMP uses 8-octet messages */
26565181Sbrian              log_Printf(LogFILTER, " error: IGMP must be at least 8 octets\n");
26662977Sbrian              return 1;
26765181Sbrian            }
26862977Sbrian            estab = syn = finrst = -1;
26962977Sbrian            sport = ntohs(0);
27062977Sbrian            break;
27149374Sbrian#endif
27262977Sbrian          case IPPROTO_UDP:
27362977Sbrian          case IPPROTO_IPIP:
27462977Sbrian            cproto = P_UDP;
27565181Sbrian            if (datalen < 8) {	/* UDP header is 8 octets */
27665181Sbrian              log_Printf(LogFILTER, " error: UDP must be at least 8 octets\n");
27762977Sbrian              return 1;
27865181Sbrian            }
27965181Sbrian
28062977Sbrian            uh = (const struct udphdr *) ptop;
28162977Sbrian            sport = ntohs(uh->uh_sport);
28262977Sbrian            dport = ntohs(uh->uh_dport);
28362977Sbrian            estab = syn = finrst = -1;
28462977Sbrian            if (log_IsKept(LogDEBUG))
28562977Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
28662977Sbrian                       sport, dport);
28762977Sbrian            break;
28862977Sbrian          case IPPROTO_TCP:
28962977Sbrian            cproto = P_TCP;
29062977Sbrian            th = (const struct tcphdr *) ptop;
29162977Sbrian            /* TCP headers are variable length.  The following code
29262977Sbrian             * ensures that the TCP header length isn't de-referenced if
29362977Sbrian             * the datagram is too short
29462977Sbrian             */
29565181Sbrian            if (datalen < 20 || datalen < (th->th_off << 2)) {
29665181Sbrian              log_Printf(LogFILTER, " error: TCP header incorrect\n");
29762977Sbrian              return 1;
29865181Sbrian            }
29962977Sbrian            sport = ntohs(th->th_sport);
30062977Sbrian            dport = ntohs(th->th_dport);
30162977Sbrian            estab = (th->th_flags & TH_ACK);
30262977Sbrian            syn = (th->th_flags & TH_SYN);
30362977Sbrian            finrst = (th->th_flags & (TH_FIN|TH_RST));
30462977Sbrian            if (log_IsKept(LogDEBUG)) {
30562977Sbrian              if (!estab)
30662977Sbrian                snprintf(dbuff, sizeof dbuff,
30762977Sbrian                         "flags = %02x, sport = %d, dport = %d",
30862977Sbrian                         th->th_flags, sport, dport);
30962977Sbrian              else
31062977Sbrian                *dbuff = '\0';
31162977Sbrian            }
31262977Sbrian            break;
31362977Sbrian          default:
31465181Sbrian            log_Printf(LogFILTER, " error: unknown protocol\n");
31562977Sbrian            return 1;		/* We'll block unknown type of packet */
31662977Sbrian          }
31726516Sbrian
31862977Sbrian          if (log_IsKept(LogDEBUG)) {
31962977Sbrian            if (estab != -1) {
32062977Sbrian              len = strlen(dbuff);
32162977Sbrian              snprintf(dbuff + len, sizeof dbuff - len,
32262977Sbrian                       ", estab = %d, syn = %d, finrst = %d",
32362977Sbrian                       estab, syn, finrst);
32462977Sbrian            }
32562977Sbrian            log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
32662977Sbrian                       filter_Proto2Nam(cproto), dbuff);
32762977Sbrian          }
32862977Sbrian          gotinfo = 1;
32962977Sbrian        }
33062977Sbrian        if (log_IsKept(LogDEBUG)) {
33162977Sbrian          if (fp->f_srcop != OP_NONE) {
33262977Sbrian            snprintf(dbuff, sizeof dbuff, ", src %s %d",
33362977Sbrian                     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
33462977Sbrian            len = strlen(dbuff);
33562977Sbrian          } else
33662977Sbrian            len = 0;
33762977Sbrian          if (fp->f_dstop != OP_NONE) {
33862977Sbrian            snprintf(dbuff + len, sizeof dbuff - len,
33962977Sbrian                     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
34062977Sbrian                     fp->f_dstport);
34162977Sbrian          } else if (!len)
34262977Sbrian            *dbuff = '\0';
34349140Sbrian
34462977Sbrian          log_Printf(LogDEBUG, "  rule = %d: Address match, "
34562977Sbrian                     "check against proto %s%s, action = %s\n",
34662977Sbrian                     n, filter_Proto2Nam(fp->f_proto),
34762977Sbrian                     dbuff, filter_Action2Nam(fp->f_action));
34862977Sbrian        }
34949140Sbrian
35062977Sbrian        if (cproto == fp->f_proto) {
35162977Sbrian          if ((fp->f_srcop == OP_NONE ||
35262977Sbrian               PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
35362977Sbrian              (fp->f_dstop == OP_NONE ||
35462977Sbrian               PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
35562977Sbrian              (fp->f_estab == 0 || estab) &&
35662977Sbrian              (fp->f_syn == 0 || syn) &&
35762977Sbrian              (fp->f_finrst == 0 || finrst)) {
35862977Sbrian            match = 1;
35962977Sbrian          }
36062977Sbrian        }
36149140Sbrian      } else {
36262977Sbrian        /* Address is matched and no protocol specified. Make a decision. */
36362977Sbrian        log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
36462977Sbrian                   filter_Action2Nam(fp->f_action));
36562977Sbrian        match = 1;
3666059Samurai      }
36749140Sbrian    } else
36849140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
36949140Sbrian
37049140Sbrian    if (match != fp->f_invert) {
37149140Sbrian      /* Take specified action */
37249140Sbrian      if (fp->f_action < A_NONE)
37362977Sbrian        fp = &filter->rule[n = fp->f_action];
37465181Sbrian      else {
37562977Sbrian        if (fp->f_action == A_PERMIT) {
37662977Sbrian          if (psecs != NULL)
37762977Sbrian            *psecs = fp->timeout;
37865181Sbrian          if (strcmp(filter->name, "DIAL") == 0) {
37965181Sbrian            /* If dial filter then even print out accept packets */
38065181Sbrian            if (log_IsKept(LogFILTER)) {
38165181Sbrian              snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
38265181Sbrian              log_Printf(LogFILTER, "%sbound rule = %d accept %s "
38365181Sbrian                         "src = %s/%d dst = %s/%d\n",
38465181Sbrian                         filter->name, n, filter_Proto2Nam(cproto),
38565181Sbrian                         inet_ntoa(pip->ip_src), sport, dstip, dport);
38665181Sbrian            }
38765181Sbrian          }
38862977Sbrian          return 0;
38965181Sbrian        } else {
39065181Sbrian          if (log_IsKept(LogFILTER)) {
39165181Sbrian            snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
39265181Sbrian            log_Printf(LogFILTER,
39365181Sbrian                       "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n",
39465181Sbrian                       filter->name, n, filter_Proto2Nam(cproto),
39565181Sbrian                       inet_ntoa(pip->ip_src), sport, dstip, dport);
39665181Sbrian          }
39765181Sbrian          return 1;
39865181Sbrian        }		/* Explict math.  Deny this packet */
39965181Sbrian      }
40049140Sbrian    } else {
40149140Sbrian      n++;
4026059Samurai      fp++;
4036059Samurai    }
4046059Samurai  }
40565181Sbrian
40665181Sbrian  if (log_IsKept(LogFILTER)) {
40765181Sbrian    snprintf(dstip, sizeof dstip, "%s", inet_ntoa(pip->ip_dst));
40865181Sbrian    log_Printf(LogFILTER,
40965181Sbrian               "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n",
41065181Sbrian               filter->name, filter_Proto2Nam(cproto),
41165181Sbrian               inet_ntoa(pip->ip_src), sport, dstip, dport);
41265181Sbrian  }
41365181Sbrian
41462977Sbrian  return 1;		/* No rule is mached. Deny this packet */
4156059Samurai}
4166059Samurai
41736285Sbrian#ifdef notdef
4186059Samuraistatic void
41946828SbrianIcmpError(struct ip *pip, int code)
4206059Samurai{
4216059Samurai  struct mbuf *bp;
4226059Samurai
4236059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
42454912Sbrian    bp = m_get(m_len, MB_IPIN);
42554912Sbrian    memcpy(MBUF_CTOP(bp), ptr, m_len);
42636285Sbrian    vj_SendFrame(bp);
42754912Sbrian    ipcp_AddOutOctets(m_len);
4286059Samurai  }
42936285Sbrian}
4306059Samurai#endif
4316059Samurai
43258033Sbrianstatic void
43358033Sbrianip_LogDNS(const struct udphdr *uh, const char *direction)
43458033Sbrian{
43558033Sbrian  struct dns_header header;
43658033Sbrian  const u_short *pktptr;
43758033Sbrian  const u_char *ptr;
43858033Sbrian  u_short *hptr;
43958033Sbrian  int len;
44058033Sbrian
44158033Sbrian  ptr = (const char *)uh + sizeof *uh;
44258033Sbrian  len = ntohs(uh->uh_ulen) - sizeof *uh;
44358033Sbrian  if (len < sizeof header + 5)		/* rfc1024 */
44458033Sbrian    return;
44558033Sbrian
44658033Sbrian  pktptr = (const u_short *)ptr;
44758033Sbrian  hptr = (u_short *)&header;
44858033Sbrian  ptr += sizeof header;
44958033Sbrian  len -= sizeof header;
45058033Sbrian
45158033Sbrian  while (pktptr < (const u_short *)ptr) {
45262977Sbrian    *hptr++ = ntohs(*pktptr);		/* Careful of macro side-effects ! */
45358033Sbrian    pktptr++;
45458033Sbrian  }
45558033Sbrian
45658033Sbrian  if (header.opcode == OPCODE_QUERY && header.qr == 0) {
45758033Sbrian    /* rfc1035 */
45858033Sbrian    char name[MAXHOSTNAMELEN + 1], *n;
45958033Sbrian    const char *qtype, *qclass;
46058033Sbrian    const u_char *end;
46158033Sbrian
46258033Sbrian    n = name;
46358033Sbrian    end = ptr + len - 4;
46458033Sbrian    if (end - ptr > MAXHOSTNAMELEN)
46558033Sbrian      end = ptr + MAXHOSTNAMELEN;
46658033Sbrian    while (ptr < end) {
46758033Sbrian      len = *ptr++;
46858033Sbrian      if (len > end - ptr)
46958033Sbrian        len = end - ptr;
47058033Sbrian      if (n != name)
47158033Sbrian        *n++ = '.';
47258033Sbrian      memcpy(n, ptr, len);
47358033Sbrian      ptr += len;
47458033Sbrian      n += len;
47558033Sbrian    }
47658033Sbrian    *n = '\0';
47758033Sbrian    qtype = dns_Qtype2Txt(ntohs(*(const u_short *)end));
47858033Sbrian    qclass = dns_Qclass2Txt(ntohs(*(const u_short *)(end + 2)));
47958033Sbrian
48058033Sbrian    log_Printf(LogDNS, "%sbound query %s %s %s\n",
48158033Sbrian               direction, qclass, qtype, name);
48258033Sbrian  }
48358033Sbrian}
48458033Sbrian
4856059Samurai/*
4866059Samurai *  For debugging aid.
4876059Samurai */
4886059Samuraiint
48962778SbrianPacketCheck(struct bundle *bundle, unsigned char *cp, int nb,
49062977Sbrian            struct filter *filter, const char *prefix, unsigned *psecs)
4916059Samurai{
49258033Sbrian  static const char *const TcpFlags[] = {
49358033Sbrian    "FIN", "SYN", "RST", "PSH", "ACK", "URG"
49458033Sbrian  };
4956059Samurai  struct ip *pip;
4966059Samurai  struct tcphdr *th;
4976059Samurai  struct udphdr *uh;
4986059Samurai  struct icmp *icmph;
49962778Sbrian  unsigned char *ptop;
50058033Sbrian  int mask, len, n, pri, logit, loglen, result;
50137010Sbrian  char logbuf[200];
5026059Samurai
50358776Sbrian  logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
50458776Sbrian          (!filter || filter->logok);
50526692Sbrian  loglen = 0;
50658033Sbrian  pri = 0;
5076059Samurai
50858033Sbrian  pip = (struct ip *)cp;
50958033Sbrian  uh = NULL;
5108857Srgrimes
51126692Sbrian  if (logit && loglen < sizeof logbuf) {
51262778Sbrian    if (prefix)
51362778Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix);
51462778Sbrian    else if (filter)
51558776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
51658776Sbrian    else
51758776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
51828679Sbrian    loglen += strlen(logbuf + loglen);
51926692Sbrian  }
5206059Samurai  ptop = (cp + (pip->ip_hl << 2));
5216059Samurai
5226059Samurai  switch (pip->ip_p) {
5236059Samurai  case IPPROTO_ICMP:
52426692Sbrian    if (logit && loglen < sizeof logbuf) {
52562778Sbrian      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - sizeof *icmph;
52628679Sbrian      icmph = (struct icmp *) ptop;
52728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
52862977Sbrian               "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
52928679Sbrian      loglen += strlen(logbuf + loglen);
53028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
53162977Sbrian               "%s:%d (%d/%d)", inet_ntoa(pip->ip_dst), icmph->icmp_type,
53262778Sbrian               len, nb);
53328679Sbrian      loglen += strlen(logbuf + loglen);
5346059Samurai    }
5356059Samurai    break;
53651048Sbrian
5376059Samurai  case IPPROTO_UDP:
53851048Sbrian    uh = (struct udphdr *) ptop;
53961430Sbrian    if (pip->ip_tos == IPTOS_LOWDELAY && bundle->ncp.ipcp.cfg.urgent.tos)
54051048Sbrian      pri++;
54151048Sbrian
54251048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
54351048Sbrian        ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
54451048Sbrian                          ntohs(uh->uh_dport)))
54551048Sbrian      pri++;
54651048Sbrian
54726692Sbrian    if (logit && loglen < sizeof logbuf) {
54862778Sbrian      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - sizeof *uh;
54928679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
55062977Sbrian               "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
55128679Sbrian      loglen += strlen(logbuf + loglen);
55228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
55362977Sbrian               "%s:%d (%d/%d)", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport),
55462977Sbrian               len, nb);
55528679Sbrian      loglen += strlen(logbuf + loglen);
5566059Samurai    }
55762778Sbrian
55862778Sbrian    if (Enabled(bundle, OPT_FILTERDECAP) &&
55962778Sbrian        ptop[sizeof *uh] == HDLC_ADDR && ptop[sizeof *uh + 1] == HDLC_UI) {
56062778Sbrian      u_short proto;
56162778Sbrian      const char *type;
56262778Sbrian
56362778Sbrian      memcpy(&proto, ptop + sizeof *uh + 2, sizeof proto);
56462778Sbrian      type = NULL;
56562778Sbrian
56662778Sbrian      switch (ntohs(proto)) {
56762778Sbrian        case PROTO_IP:
56862778Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
56962778Sbrian          result = PacketCheck(bundle, ptop + sizeof *uh + 4,
57062778Sbrian                               nb - (ptop - cp) - sizeof *uh - 4, filter,
57162977Sbrian                               logbuf, psecs);
57262778Sbrian          if (result != -2)
57362778Sbrian              return result;
57462778Sbrian          type = "IP";
57562778Sbrian          break;
57662778Sbrian
57762778Sbrian        case PROTO_VJUNCOMP: type = "compressed VJ";   break;
57862778Sbrian        case PROTO_VJCOMP:   type = "uncompressed VJ"; break;
57962778Sbrian        case PROTO_MP:       type = "Multi-link"; break;
58062778Sbrian        case PROTO_ICOMPD:   type = "Individual link CCP"; break;
58162778Sbrian        case PROTO_COMPD:    type = "CCP"; break;
58262778Sbrian        case PROTO_IPCP:     type = "IPCP"; break;
58362778Sbrian        case PROTO_LCP:      type = "LCP"; break;
58462778Sbrian        case PROTO_PAP:      type = "PAP"; break;
58562778Sbrian        case PROTO_CBCP:     type = "CBCP"; break;
58662778Sbrian        case PROTO_LQR:      type = "LQR"; break;
58762778Sbrian        case PROTO_CHAP:     type = "CHAP"; break;
58862778Sbrian      }
58962778Sbrian      if (type) {
59062778Sbrian        snprintf(logbuf + loglen, sizeof logbuf - loglen,
59162778Sbrian                 " - %s data", type);
59262778Sbrian        loglen += strlen(logbuf + loglen);
59362778Sbrian      }
59462778Sbrian    }
59562778Sbrian
5966059Samurai    break;
59751048Sbrian
59851809Sbrian#ifdef IPPROTO_GRE
59951809Sbrian  case IPPROTO_GRE:
60051809Sbrian    if (logit && loglen < sizeof logbuf) {
60162778Sbrian      len = ntohs(pip->ip_len) - (pip->ip_hl << 2);
60251809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
60351809Sbrian          "GRE: %s ---> ", inet_ntoa(pip->ip_src));
60451809Sbrian      loglen += strlen(logbuf + loglen);
60551809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
60662778Sbrian              "%s (%d/%d)", inet_ntoa(pip->ip_dst), len, nb);
60751809Sbrian      loglen += strlen(logbuf + loglen);
60851809Sbrian    }
60951809Sbrian    break;
61051809Sbrian#endif
61151809Sbrian
61249374Sbrian#ifdef IPPROTO_OSPFIGP
61349372Sbrian  case IPPROTO_OSPFIGP:
61449372Sbrian    if (logit && loglen < sizeof logbuf) {
61562778Sbrian      len = ntohs(pip->ip_len) - (pip->ip_hl << 2);
61649372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
61762977Sbrian               "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
61849372Sbrian      loglen += strlen(logbuf + loglen);
61949372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
62062977Sbrian               "%s (%d/%d)", inet_ntoa(pip->ip_dst), len, nb);
62149372Sbrian      loglen += strlen(logbuf + loglen);
62249372Sbrian    }
62349372Sbrian    break;
62449374Sbrian#endif
62551048Sbrian
62636961Sbrian  case IPPROTO_IPIP:
62736961Sbrian    if (logit && loglen < sizeof logbuf) {
62836961Sbrian      uh = (struct udphdr *) ptop;
62936961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
63062977Sbrian               "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src),
63162977Sbrian               ntohs(uh->uh_sport));
63236961Sbrian      loglen += strlen(logbuf + loglen);
63336961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
63462977Sbrian               "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
63536961Sbrian      loglen += strlen(logbuf + loglen);
63636961Sbrian    }
63736961Sbrian    break;
63851048Sbrian
63936961Sbrian  case IPPROTO_IGMP:
64036961Sbrian    if (logit && loglen < sizeof logbuf) {
64136961Sbrian      uh = (struct udphdr *) ptop;
64236961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
64362977Sbrian               "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src),
64462977Sbrian               ntohs(uh->uh_sport));
64536961Sbrian      loglen += strlen(logbuf + loglen);
64636961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
64762977Sbrian               "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
64836961Sbrian      loglen += strlen(logbuf + loglen);
64936961Sbrian    }
65036961Sbrian    break;
65151048Sbrian
6526059Samurai  case IPPROTO_TCP:
65328679Sbrian    th = (struct tcphdr *) ptop;
65461430Sbrian    if (pip->ip_tos == IPTOS_LOWDELAY && bundle->ncp.ipcp.cfg.urgent.tos)
65550867Sbrian      pri++;
65651048Sbrian
65751048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
65851048Sbrian        ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
65951048Sbrian                          ntohs(th->th_dport)))
66050867Sbrian      pri++;
66150867Sbrian
66226692Sbrian    if (logit && loglen < sizeof logbuf) {
6636059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
66428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
66562977Sbrian           "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
66628679Sbrian      loglen += strlen(logbuf + loglen);
66728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
66862977Sbrian               "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
66928679Sbrian      loglen += strlen(logbuf + loglen);
6706059Samurai      n = 0;
6716059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
67262977Sbrian        if (th->th_flags & mask) {
67362977Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
67462977Sbrian          loglen += strlen(logbuf + loglen);
67562977Sbrian        }
67662977Sbrian        n++;
6776059Samurai      }
67828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
67962977Sbrian               "  seq:%lx  ack:%lx (%d/%d)",
68062977Sbrian               (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
68128679Sbrian      loglen += strlen(logbuf + loglen);
6826059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
68362977Sbrian        u_short *sp;
6846059Samurai
68562977Sbrian        ptop += 20;
68662977Sbrian        sp = (u_short *) ptop;
68762977Sbrian        if (ntohs(sp[0]) == 0x0204) {
68862977Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen,
68962977Sbrian                   " MSS = %d", ntohs(sp[1]));
69062977Sbrian          loglen += strlen(logbuf + loglen);
69162977Sbrian        }
6926059Samurai      }
6936059Samurai    }
6946059Samurai    break;
69562778Sbrian
69662778Sbrian  default:
69762778Sbrian    if (prefix)
69862778Sbrian      return -2;
6996059Samurai  }
70026692Sbrian
70162977Sbrian  if (filter && FilterCheck(pip, filter, psecs)) {
70231142Sbrian    if (logit)
70336285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
70436285Sbrian#ifdef notdef
70528679Sbrian    if (direction == 0)
70628679Sbrian      IcmpError(pip, pri);
70736285Sbrian#endif
70858033Sbrian    result = -1;
7096059Samurai  } else {
71036285Sbrian    /* Check Keep Alive filter */
71158033Sbrian    if (logit && log_IsKept(LogTCPIP)) {
71262977Sbrian      unsigned alivesecs;
71362977Sbrian
71462977Sbrian      alivesecs = 0;
71562977Sbrian      if (filter && FilterCheck(pip, &bundle->filter.alive, &alivesecs))
71636285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
71762977Sbrian      else if (psecs != NULL) {
71862977Sbrian        if(*psecs == 0)
71962977Sbrian          *psecs = alivesecs;
72062977Sbrian        if (*psecs) {
72162977Sbrian          if (*psecs != alivesecs)
72262977Sbrian            log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n",
72362977Sbrian                       logbuf, *psecs, alivesecs);
72462977Sbrian          else
72562977Sbrian            log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs);
72662977Sbrian        } else
72762977Sbrian          log_Printf(LogTCPIP, "%s\n", logbuf);
72862977Sbrian      }
7296735Samurai    }
73058033Sbrian    result = pri;
7316059Samurai  }
73258033Sbrian
73358776Sbrian  if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
73458033Sbrian    ip_LogDNS(uh, filter->name);
73558033Sbrian
73658033Sbrian  return result;
7376059Samurai}
7386059Samurai
73946686Sbrianstruct mbuf *
74046686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
74136285Sbrian{
7426059Samurai  int nb, nw;
74331343Sbrian  struct tun_data tun;
74446686Sbrian  struct ip *pip;
74556413Sbrian  char *data;
74662977Sbrian  unsigned secs, alivesecs;
7476059Samurai
74846686Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
74946686Sbrian    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
75054912Sbrian    m_freem(bp);
75146686Sbrian    return NULL;
7526059Samurai  }
7536059Samurai
75454912Sbrian  m_settype(bp, MB_IPIN);
75554912Sbrian  nb = m_length(bp);
75647168Sbrian  if (nb > sizeof tun.data) {
75747168Sbrian    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
75847168Sbrian               l->name, nb, (int)(sizeof tun.data));
75954912Sbrian    m_freem(bp);
76047168Sbrian    return NULL;
76147168Sbrian  }
76246686Sbrian  mbuf_Read(bp, tun.data, nb);
76326031Sbrian
76462977Sbrian  secs = 0;
76562977Sbrian  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in, NULL, &secs) < 0)
76646686Sbrian    return NULL;
76726031Sbrian
76846686Sbrian  pip = (struct ip *)tun.data;
76962977Sbrian  alivesecs = 0;
77062977Sbrian  if (!FilterCheck(pip, &bundle->filter.alive, &alivesecs)) {
77162977Sbrian    if (secs == 0)
77262977Sbrian      secs = alivesecs;
77362977Sbrian    bundle_StartIdleTimer(bundle, secs);
77462977Sbrian  }
77526031Sbrian
77646686Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
77736285Sbrian
77856413Sbrian  if (bundle->dev.header) {
77962977Sbrian    tun.header.family = htonl(AF_INET);
78056413Sbrian    nb += sizeof tun - sizeof tun.data;
78156413Sbrian    data = (char *)&tun;
78256413Sbrian  } else
78356413Sbrian    data = tun.data;
78456413Sbrian
78556413Sbrian  nw = write(bundle->dev.fd, data, nb);
78646686Sbrian  if (nw != nb) {
78746686Sbrian    if (nw == -1)
78847168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
78947168Sbrian                 l->name, nb, strerror(errno));
79046686Sbrian    else
79147168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
79246686Sbrian  }
79336285Sbrian
79446686Sbrian  return NULL;
7956059Samurai}
7966059Samurai
7976059Samuraivoid
79838557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
7996059Samurai{
8006059Samurai  struct mbuf *bp;
8016059Samurai
80250867Sbrian  if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
80338557Sbrian    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
80438557Sbrian  else {
80546686Sbrian    /*
80646686Sbrian     * We allocate an extra 6 bytes, four at the front and two at the end.
80746686Sbrian     * This is an optimisation so that we need to do less work in
80854912Sbrian     * m_prepend() in acf_LayerPush() and proto_LayerPush() and
80946686Sbrian     * appending in hdlc_LayerPush().
81046686Sbrian     */
81154912Sbrian    bp = m_get(count + 6, MB_IPOUT);
81254912Sbrian    bp->m_offset += 4;
81354912Sbrian    bp->m_len -= 6;
81438557Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
81554912Sbrian    m_enqueue(ipcp->Queue + pri, bp);
81638557Sbrian  }
8176059Samurai}
8186059Samurai
81938544Sbrianvoid
82038557Sbrianip_DeleteQueue(struct ipcp *ipcp)
82138544Sbrian{
82238544Sbrian  struct mqueue *queue;
82338544Sbrian
82450867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
82538544Sbrian    while (queue->top)
82654912Sbrian      m_freem(m_dequeue(queue));
82738544Sbrian}
82838544Sbrian
82954912Sbriansize_t
83038557Sbrianip_QueueLen(struct ipcp *ipcp)
8317001Samurai{
8327001Samurai  struct mqueue *queue;
83354912Sbrian  size_t result;
83428679Sbrian
83554912Sbrian  result = 0;
83650867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
83754912Sbrian    result += queue->len;
83836285Sbrian
83936285Sbrian  return result;
8407001Samurai}
8417001Samurai
84236285Sbrianint
84346686Sbrianip_PushPacket(struct link *l, struct bundle *bundle)
8446059Samurai{
84538557Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
8466059Samurai  struct mqueue *queue;
8476059Samurai  struct mbuf *bp;
84846686Sbrian  struct ip *pip;
84954912Sbrian  int m_len;
85062977Sbrian  u_int32_t secs = 0;
85162977Sbrian  unsigned alivesecs = 0;
8526059Samurai
85338557Sbrian  if (ipcp->fsm.state != ST_OPENED)
85436285Sbrian    return 0;
85536285Sbrian
85650867Sbrian  queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
85750867Sbrian  do {
8586059Samurai    if (queue->top) {
85962977Sbrian      bp = m_dequeue(queue);
86062977Sbrian      bp = mbuf_Read(bp, &secs, sizeof secs);
86162977Sbrian      bp = m_pullup(bp);
86254912Sbrian      m_len = m_length(bp);
86346686Sbrian      pip = (struct ip *)MBUF_CTOP(bp);
86462977Sbrian      if (!FilterCheck(pip, &bundle->filter.alive, &alivesecs)) {
86562977Sbrian        if (secs == 0)
86662977Sbrian          secs = alivesecs;
86762977Sbrian        bundle_StartIdleTimer(bundle, secs);
86862977Sbrian      }
86950867Sbrian      link_PushPacket(l, bp, bundle, 0, PROTO_IP);
87054912Sbrian      ipcp_AddOutOctets(ipcp, m_len);
87146686Sbrian      return 1;
8726059Samurai    }
87350867Sbrian  } while (queue-- != ipcp->Queue);
87436285Sbrian
87536285Sbrian  return 0;
8766059Samurai}
877