178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD$
296059Samurai */
3078189Sbrian
3143313Sbrian#include <sys/param.h>
3231195Sbrian#include <sys/socket.h>
3330715Sbrian#include <netinet/in.h>
346059Samurai#include <netinet/in_systm.h>
356059Samurai#include <netinet/ip.h>
3681634Sbrian#ifndef NOINET6
3781634Sbrian#include <netinet/icmp6.h>
3881634Sbrian#include <netinet/ip6.h>
3981634Sbrian#endif
406059Samurai#include <netinet/ip_icmp.h>
416059Samurai#include <netinet/udp.h>
426059Samurai#include <netinet/tcp.h>
4336285Sbrian#include <sys/un.h>
4430715Sbrian
4530092Sbrian#include <errno.h>
4681634Sbrian#include <netdb.h>
4730715Sbrian#include <stdio.h>
4830715Sbrian#include <string.h>
4946686Sbrian#include <termios.h>
5030715Sbrian#include <unistd.h>
5130715Sbrian
5246686Sbrian#include "layer.h"
5346686Sbrian#include "proto.h"
5430715Sbrian#include "mbuf.h"
5530715Sbrian#include "log.h"
5630715Sbrian#include "defs.h"
5730715Sbrian#include "timer.h"
5830715Sbrian#include "fsm.h"
5936285Sbrian#include "lqr.h"
6030715Sbrian#include "hdlc.h"
6136285Sbrian#include "throughput.h"
6236285Sbrian#include "iplist.h"
6336285Sbrian#include "slcompress.h"
6481634Sbrian#include "ncpaddr.h"
6581634Sbrian#include "ip.h"
6636285Sbrian#include "ipcp.h"
676059Samurai#include "filter.h"
6836285Sbrian#include "descriptor.h"
6936285Sbrian#include "lcp.h"
7036285Sbrian#include "ccp.h"
7136285Sbrian#include "link.h"
7236285Sbrian#include "mp.h"
7343313Sbrian#ifndef NORADIUS
7443313Sbrian#include "radius.h"
7543313Sbrian#endif
7681634Sbrian#include "ipv6cp.h"
7781634Sbrian#include "ncp.h"
7836285Sbrian#include "bundle.h"
7931195Sbrian#include "tun.h"
806059Samurai
8158033Sbrian
8258033Sbrian#define OPCODE_QUERY	0
8358033Sbrian#define OPCODE_IQUERY	1
8458033Sbrian#define OPCODE_STATUS	2
8558033Sbrian
8658033Sbrianstruct dns_header {
8758033Sbrian  u_short id;
8858033Sbrian  unsigned qr : 1;
8958033Sbrian  unsigned opcode : 4;
9058033Sbrian  unsigned aa : 1;
9158033Sbrian  unsigned tc : 1;
9258033Sbrian  unsigned rd : 1;
9358033Sbrian  unsigned ra : 1;
9458033Sbrian  unsigned z : 3;
9558033Sbrian  unsigned rcode : 4;
9658033Sbrian  u_short qdcount;
9758033Sbrian  u_short ancount;
9858033Sbrian  u_short nscount;
9958033Sbrian  u_short arcount;
10055146Sbrian};
1016059Samurai
10258033Sbrianstatic const char *
10358033Sbriandns_Qclass2Txt(u_short qclass)
10458033Sbrian{
10558033Sbrian  static char failure[6];
10658033Sbrian  struct {
10758033Sbrian    u_short id;
10858033Sbrian    const char *txt;
10958033Sbrian  } qtxt[] = {
11058033Sbrian    /* rfc1035 */
11158033Sbrian    { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
11258033Sbrian  };
113134789Sbrian  unsigned f;
11458033Sbrian
11558033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
11658033Sbrian    if (qtxt[f].id == qclass)
11758033Sbrian      return qtxt[f].txt;
11858033Sbrian
11958034Sbrian  return HexStr(qclass, failure, sizeof failure);
12058033Sbrian}
12158033Sbrian
12258033Sbrianstatic const char *
12358033Sbriandns_Qtype2Txt(u_short qtype)
12458033Sbrian{
12558033Sbrian  static char failure[6];
12658033Sbrian  struct {
12758033Sbrian    u_short id;
12858033Sbrian    const char *txt;
12958033Sbrian  } qtxt[] = {
13058033Sbrian    /* rfc1035/rfc1700 */
13158033Sbrian    { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
13258033Sbrian    { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
13358033Sbrian    { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
13458033Sbrian    { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
13558033Sbrian    { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
13658033Sbrian    { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
13758033Sbrian    { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
13858033Sbrian    { 254, "MAILA" }, { 255, "*" }
13958033Sbrian  };
140134789Sbrian  unsigned f;
14158033Sbrian
14258033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
14358033Sbrian    if (qtxt[f].id == qtype)
14458033Sbrian      return qtxt[f].txt;
14558033Sbrian
14658034Sbrian  return HexStr(qtype, failure, sizeof failure);
14758033Sbrian}
14858033Sbrian
14949140Sbrianstatic __inline int
15028679SbrianPortMatch(int op, u_short pport, u_short rport)
1516059Samurai{
1526059Samurai  switch (op) {
15349140Sbrian  case OP_EQ:
15462977Sbrian    return pport == rport;
1556059Samurai  case OP_GT:
15662977Sbrian    return pport > rport;
1576059Samurai  case OP_LT:
15862977Sbrian    return pport < rport;
1596059Samurai  default:
16062977Sbrian    return 0;
1616059Samurai  }
1626059Samurai}
1636059Samurai
1646059Samurai/*
165129175Sdds * Return a text string representing the cproto protocol number.
166129175Sdds *
167129175Sdds * The purpose of this routine is calculate this result, for
168129175Sdds * the many times it is needed in FilterCheck, only on demand
169129175Sdds * (i.e. when the corresponding logging functions are invoked).
170129175Sdds *
171129175Sdds * This optimization saves, over the previous implementation, which
172129175Sdds * calculated prototxt at the beginning of FilterCheck, an
173129175Sdds * open/read/close system call sequence per packet, approximately
174129175Sdds * halving the ppp system overhead and reducing the overall (u + s)
175129175Sdds * time by 38%.
176129175Sdds *
177129175Sdds * The caching performed here is just a side effect.
178129175Sdds */
179129175Sddsstatic const char *
180129175Sddsprototxt(int cproto)
181129175Sdds{
182129175Sdds  static int oproto = -1;
183129175Sdds  static char protobuff[16] = "-1";
184129175Sdds  struct protoent *pe;
185129175Sdds
186129175Sdds  if (cproto == oproto)
187129175Sdds	return protobuff;
188129175Sdds  if ((pe = getprotobynumber(cproto)) == NULL)
189129175Sdds    snprintf(protobuff, sizeof protobuff, "%d", cproto);
190129175Sdds  else
191129175Sdds    snprintf(protobuff, sizeof protobuff, "%s", pe->p_name);
192129175Sdds  oproto = cproto;
193129175Sdds  return (protobuff);
194129175Sdds}
195129175Sdds
196129175Sdds/*
19781634Sbrian * Check a packet against the given filter
19881634Sbrian * Returns 0 to accept the packet, non-zero to drop the packet.
19981634Sbrian * If psecs is not NULL, populate it with the timeout associated
20081634Sbrian * with the filter rule matched.
20149140Sbrian *
20281634Sbrian * If filtering is enabled, the initial fragment of a datagram must
20381634Sbrian * contain the complete protocol header, and subsequent fragments
20481634Sbrian * must not attempt to over-write it.
20581634Sbrian *
20681634Sbrian * One (and only one) of pip or pip6 must be set.
2076059Samurai */
20881634Sbrianint
209134875SbrianFilterCheck(const unsigned char *packet,
210134875Sbrian#ifdef NOINET6
211134875Sbrian	    u_int32_t family __unused,
212134875Sbrian#else
213134875Sbrian	    u_int32_t family,
214134875Sbrian#endif
21581634Sbrian            const struct filter *filter, unsigned *psecs)
2166059Samurai{
21749140Sbrian  int gotinfo;			/* true if IP payload decoded */
21881634Sbrian  int cproto;			/* IPPROTO_* protocol number if (gotinfo) */
21949140Sbrian  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
22049140Sbrian  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
22149140Sbrian  int n;			/* filter rule to process */
22249140Sbrian  int len;			/* bytes used in dbuff */
22349140Sbrian  int didname;			/* true if filter header printed */
22449140Sbrian  int match;			/* true if condition matched */
22581634Sbrian  int mindata;			/* minimum data size or zero */
22649140Sbrian  const struct filterent *fp = filter->rule;
227129175Sdds  char dbuff[100], dstip[16];
22881634Sbrian  struct ncpaddr srcaddr, dstaddr;
22981634Sbrian  const char *payload;		/* IP payload */
23081634Sbrian  int datalen;			/* IP datagram length */
2316059Samurai
23249140Sbrian  if (fp->f_action == A_NONE)
23362977Sbrian    return 0;		/* No rule is given. Permit this packet */
23436285Sbrian
23581634Sbrian#ifndef NOINET6
23681634Sbrian  if (family == AF_INET6) {
23781634Sbrian    const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
23881634Sbrian
23981634Sbrian    ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
24081634Sbrian    ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
24181738Sbrian    datalen = ntohs(pip6->ip6_plen);
24281738Sbrian    payload = packet + sizeof *pip6;
24381634Sbrian    cproto = pip6->ip6_nxt;
24481634Sbrian  } else
24581634Sbrian#endif
24681634Sbrian  {
24781634Sbrian    /*
24881634Sbrian     * Deny any packet fragment that tries to over-write the header.
24981634Sbrian     * Since we no longer have the real header available, punt on the
25081634Sbrian     * largest normal header - 20 bytes for TCP without options, rounded
25181634Sbrian     * up to the next possible fragment boundary.  Since the smallest
25281634Sbrian     * `legal' MTU is 576, and the smallest recommended MTU is 296, any
25381634Sbrian     * fragmentation within this range is dubious at best
25481634Sbrian     */
25581634Sbrian    const struct ip *pip = (const struct ip *)packet;
25681634Sbrian
25798243Sbrian    len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
25881634Sbrian    if (len > 0) {		/* Not first fragment within datagram */
25981634Sbrian      if (len < (24 >> 3)) {	/* don't allow fragment to over-write header */
26081634Sbrian        log_Printf(LogFILTER, " error: illegal header\n");
26181634Sbrian        return 1;
26281634Sbrian      }
26381634Sbrian      /* permit fragments on in and out filter */
26481634Sbrian      if (!filter->fragok) {
26581634Sbrian        log_Printf(LogFILTER, " error: illegal fragmentation\n");
26681634Sbrian        return 1;
26781634Sbrian      } else
26881634Sbrian        return 0;
26965181Sbrian    }
27098243Sbrian
27181634Sbrian    ncpaddr_setip4(&srcaddr, pip->ip_src);
27281634Sbrian    ncpaddr_setip4(&dstaddr, pip->ip_dst);
27381634Sbrian    datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
27481634Sbrian    payload = packet + (pip->ip_hl << 2);
27581634Sbrian    cproto = pip->ip_p;
27649140Sbrian  }
27781634Sbrian
278129175Sdds
27981634Sbrian  gotinfo = estab = syn = finrst = didname = 0;
28049140Sbrian  sport = dport = 0;
28181634Sbrian
28249140Sbrian  for (n = 0; n < MAXFILTERS; ) {
28349140Sbrian    if (fp->f_action == A_NONE) {
28449140Sbrian      n++;
28549140Sbrian      fp++;
28649140Sbrian      continue;
28749140Sbrian    }
28836285Sbrian
28949140Sbrian    if (!didname) {
29049140Sbrian      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
29149140Sbrian      didname = 1;
29249140Sbrian    }
2936059Samurai
29449140Sbrian    match = 0;
29581634Sbrian
29681634Sbrian    if ((ncprange_family(&fp->f_src) == AF_UNSPEC ||
29781634Sbrian         ncprange_contains(&fp->f_src, &srcaddr)) &&
29881634Sbrian        (ncprange_family(&fp->f_dst) == AF_UNSPEC ||
29981634Sbrian         ncprange_contains(&fp->f_dst, &dstaddr))) {
30081634Sbrian      if (fp->f_proto != 0) {
30162977Sbrian        if (!gotinfo) {
30262977Sbrian          const struct tcphdr *th;
30362977Sbrian          const struct udphdr *uh;
30462977Sbrian          const struct icmp *ih;
30581634Sbrian#ifndef NOINET6
30681634Sbrian          const struct icmp6_hdr *ih6;
30781634Sbrian#endif
30881634Sbrian          mindata = 0;
30981634Sbrian          sport = dport = 0;
31081634Sbrian          estab = syn = finrst = -1;
31149140Sbrian
31281634Sbrian          switch (cproto) {
31362977Sbrian          case IPPROTO_ICMP:
31481634Sbrian            mindata = 8;	/* ICMP must be at least 8 octets */
31581634Sbrian            ih = (const struct icmp *)payload;
316112660Sbrian            sport = ih->icmp_type;
31781634Sbrian            if (log_IsKept(LogDEBUG))
31881634Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
31981634Sbrian            break;
32065181Sbrian
32181634Sbrian#ifndef NOINET6
32281634Sbrian          case IPPROTO_ICMPV6:
32381634Sbrian            mindata = 8;	/* ICMP must be at least 8 octets */
32481634Sbrian            ih6 = (const struct icmp6_hdr *)payload;
325112660Sbrian            sport = ih6->icmp6_type;
32662977Sbrian            if (log_IsKept(LogDEBUG))
32762977Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
32862977Sbrian            break;
32981634Sbrian#endif
33081634Sbrian
33162977Sbrian          case IPPROTO_IGMP:
33281634Sbrian            mindata = 8;	/* IGMP uses 8-octet messages */
33362977Sbrian            break;
33481634Sbrian
33551809Sbrian#ifdef IPPROTO_GRE
33651809Sbrian          case IPPROTO_GRE:
33781634Sbrian            mindata = 2;	/* GRE uses 2-octet+ messages */
33851809Sbrian            break;
33951809Sbrian#endif
34049374Sbrian#ifdef IPPROTO_OSPFIGP
34162977Sbrian          case IPPROTO_OSPFIGP:
34281634Sbrian            mindata = 8;	/* IGMP uses 8-octet messages */
34362977Sbrian            break;
34449374Sbrian#endif
34581634Sbrian#ifndef NOINET6
34681634Sbrian          case IPPROTO_IPV6:
34781634Sbrian            mindata = 20;	/* RFC2893 Section 3.5: 5 * 32bit words */
34865846Sbrian            break;
34981634Sbrian#endif
35081634Sbrian
35162977Sbrian          case IPPROTO_UDP:
35281634Sbrian            mindata = 8;	/* UDP header is 8 octets */
35381634Sbrian            uh = (const struct udphdr *)payload;
35462977Sbrian            sport = ntohs(uh->uh_sport);
35562977Sbrian            dport = ntohs(uh->uh_dport);
35662977Sbrian            if (log_IsKept(LogDEBUG))
35762977Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
35862977Sbrian                       sport, dport);
35962977Sbrian            break;
36081634Sbrian
36162977Sbrian          case IPPROTO_TCP:
36281634Sbrian            th = (const struct tcphdr *)payload;
36381634Sbrian            /*
36481634Sbrian             * TCP headers are variable length.  The following code
36562977Sbrian             * ensures that the TCP header length isn't de-referenced if
36662977Sbrian             * the datagram is too short
36762977Sbrian             */
36865181Sbrian            if (datalen < 20 || datalen < (th->th_off << 2)) {
36965181Sbrian              log_Printf(LogFILTER, " error: TCP header incorrect\n");
37062977Sbrian              return 1;
37165181Sbrian            }
37262977Sbrian            sport = ntohs(th->th_sport);
37362977Sbrian            dport = ntohs(th->th_dport);
37462977Sbrian            estab = (th->th_flags & TH_ACK);
37562977Sbrian            syn = (th->th_flags & TH_SYN);
37662977Sbrian            finrst = (th->th_flags & (TH_FIN|TH_RST));
37762977Sbrian            if (log_IsKept(LogDEBUG)) {
37862977Sbrian              if (!estab)
37962977Sbrian                snprintf(dbuff, sizeof dbuff,
38062977Sbrian                         "flags = %02x, sport = %d, dport = %d",
38162977Sbrian                         th->th_flags, sport, dport);
38262977Sbrian              else
38362977Sbrian                *dbuff = '\0';
38462977Sbrian            }
38562977Sbrian            break;
38662977Sbrian          default:
38781634Sbrian            break;
38862977Sbrian          }
38926516Sbrian
39081634Sbrian          if (datalen < mindata) {
39181634Sbrian            log_Printf(LogFILTER, " error: proto %s must be at least"
392129175Sdds                       " %d octets\n", prototxt(cproto), mindata);
39381634Sbrian            return 1;
39481634Sbrian          }
39581634Sbrian
39662977Sbrian          if (log_IsKept(LogDEBUG)) {
39762977Sbrian            if (estab != -1) {
39862977Sbrian              len = strlen(dbuff);
39962977Sbrian              snprintf(dbuff + len, sizeof dbuff - len,
40062977Sbrian                       ", estab = %d, syn = %d, finrst = %d",
40162977Sbrian                       estab, syn, finrst);
40262977Sbrian            }
403129175Sdds            log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
404129175Sdds                       prototxt(cproto), dbuff);
40562977Sbrian          }
40662977Sbrian          gotinfo = 1;
40762977Sbrian        }
40881634Sbrian
40962977Sbrian        if (log_IsKept(LogDEBUG)) {
41062977Sbrian          if (fp->f_srcop != OP_NONE) {
41162977Sbrian            snprintf(dbuff, sizeof dbuff, ", src %s %d",
41262977Sbrian                     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
41362977Sbrian            len = strlen(dbuff);
41462977Sbrian          } else
41562977Sbrian            len = 0;
41662977Sbrian          if (fp->f_dstop != OP_NONE) {
41762977Sbrian            snprintf(dbuff + len, sizeof dbuff - len,
41862977Sbrian                     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
41962977Sbrian                     fp->f_dstport);
42062977Sbrian          } else if (!len)
42162977Sbrian            *dbuff = '\0';
42249140Sbrian
42362977Sbrian          log_Printf(LogDEBUG, "  rule = %d: Address match, "
42481634Sbrian                     "check against proto %d%s, action = %s\n",
42581634Sbrian                     n, fp->f_proto, dbuff, filter_Action2Nam(fp->f_action));
42662977Sbrian        }
42749140Sbrian
42862977Sbrian        if (cproto == fp->f_proto) {
42962977Sbrian          if ((fp->f_srcop == OP_NONE ||
43062977Sbrian               PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
43162977Sbrian              (fp->f_dstop == OP_NONE ||
43262977Sbrian               PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
43362977Sbrian              (fp->f_estab == 0 || estab) &&
43462977Sbrian              (fp->f_syn == 0 || syn) &&
43562977Sbrian              (fp->f_finrst == 0 || finrst)) {
43662977Sbrian            match = 1;
43762977Sbrian          }
43862977Sbrian        }
43949140Sbrian      } else {
44062977Sbrian        /* Address is matched and no protocol specified. Make a decision. */
44162977Sbrian        log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
44262977Sbrian                   filter_Action2Nam(fp->f_action));
44362977Sbrian        match = 1;
4446059Samurai      }
44549140Sbrian    } else
44649140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
44749140Sbrian
44849140Sbrian    if (match != fp->f_invert) {
44949140Sbrian      /* Take specified action */
45049140Sbrian      if (fp->f_action < A_NONE)
45162977Sbrian        fp = &filter->rule[n = fp->f_action];
45265181Sbrian      else {
45362977Sbrian        if (fp->f_action == A_PERMIT) {
45462977Sbrian          if (psecs != NULL)
45562977Sbrian            *psecs = fp->timeout;
45665181Sbrian          if (strcmp(filter->name, "DIAL") == 0) {
45765181Sbrian            /* If dial filter then even print out accept packets */
45865181Sbrian            if (log_IsKept(LogFILTER)) {
45981634Sbrian              snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
46065181Sbrian              log_Printf(LogFILTER, "%sbound rule = %d accept %s "
461129175Sdds                         "src = %s:%d dst = %s:%d\n", filter->name, n,
462129175Sdds                         prototxt(cproto), ncpaddr_ntoa(&srcaddr), sport,
463129175Sdds                         dstip, dport);
46465181Sbrian            }
46565181Sbrian          }
46662977Sbrian          return 0;
46765181Sbrian        } else {
46865181Sbrian          if (log_IsKept(LogFILTER)) {
46981634Sbrian            snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
47098243Sbrian            log_Printf(LogFILTER,
47198243Sbrian                       "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n",
472129175Sdds                       filter->name, n, prototxt(cproto),
47381634Sbrian                       ncpaddr_ntoa(&srcaddr), sport, dstip, dport);
47465181Sbrian          }
47598243Sbrian          return 1;
47681634Sbrian        }		/* Explict match.  Deny this packet */
47765181Sbrian      }
47849140Sbrian    } else {
47949140Sbrian      n++;
4806059Samurai      fp++;
4816059Samurai    }
4826059Samurai  }
48365181Sbrian
48465181Sbrian  if (log_IsKept(LogFILTER)) {
48581634Sbrian    snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
48698243Sbrian    log_Printf(LogFILTER,
48798243Sbrian               "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n",
488129175Sdds               filter->name, prototxt(cproto), ncpaddr_ntoa(&srcaddr),
489129175Sdds               sport, dstip, dport);
49065181Sbrian  }
49165181Sbrian
49281634Sbrian  return 1;		/* No rule matched, deny this packet */
4936059Samurai}
4946059Samurai
4956059Samuraistatic void
49658033Sbrianip_LogDNS(const struct udphdr *uh, const char *direction)
49758033Sbrian{
49858033Sbrian  struct dns_header header;
49958033Sbrian  const u_short *pktptr;
50058033Sbrian  const u_char *ptr;
50177487Sbrian  u_short *hptr, tmp;
502134789Sbrian  unsigned len;
50358033Sbrian
50458033Sbrian  ptr = (const char *)uh + sizeof *uh;
50558033Sbrian  len = ntohs(uh->uh_ulen) - sizeof *uh;
50658033Sbrian  if (len < sizeof header + 5)		/* rfc1024 */
50758033Sbrian    return;
50858033Sbrian
50958033Sbrian  pktptr = (const u_short *)ptr;
51058033Sbrian  hptr = (u_short *)&header;
51158033Sbrian  ptr += sizeof header;
51258033Sbrian  len -= sizeof header;
51358033Sbrian
51458033Sbrian  while (pktptr < (const u_short *)ptr) {
51562977Sbrian    *hptr++ = ntohs(*pktptr);		/* Careful of macro side-effects ! */
51658033Sbrian    pktptr++;
51758033Sbrian  }
51858033Sbrian
51958033Sbrian  if (header.opcode == OPCODE_QUERY && header.qr == 0) {
52058033Sbrian    /* rfc1035 */
52174049Sbrian    char namewithdot[MAXHOSTNAMELEN + 1], *n;
52258033Sbrian    const char *qtype, *qclass;
52358033Sbrian    const u_char *end;
52458033Sbrian
52574049Sbrian    n = namewithdot;
52658033Sbrian    end = ptr + len - 4;
527134789Sbrian    if (end - ptr >= (int)sizeof namewithdot)
52874049Sbrian      end = ptr + sizeof namewithdot - 1;
52958033Sbrian    while (ptr < end) {
53058033Sbrian      len = *ptr++;
531134789Sbrian      if ((int)len > end - ptr)
53258033Sbrian        len = end - ptr;
53374049Sbrian      if (n != namewithdot)
53458033Sbrian        *n++ = '.';
53558033Sbrian      memcpy(n, ptr, len);
53658033Sbrian      ptr += len;
53758033Sbrian      n += len;
53858033Sbrian    }
53958033Sbrian    *n = '\0';
54058033Sbrian
54177487Sbrian    if (log_IsKept(LogDNS)) {
54277487Sbrian      memcpy(&tmp, end, sizeof tmp);
54377487Sbrian      qtype = dns_Qtype2Txt(ntohs(tmp));
54477487Sbrian      memcpy(&tmp, end + 2, sizeof tmp);
54577487Sbrian      qclass = dns_Qclass2Txt(ntohs(tmp));
54677487Sbrian
54777487Sbrian      log_Printf(LogDNS, "%sbound query %s %s %s\n",
54877487Sbrian                 direction, qclass, qtype, namewithdot);
54977487Sbrian    }
55058033Sbrian  }
55158033Sbrian}
55258033Sbrian
5536059Samurai/*
55481634Sbrian * Check if the given packet matches the given filter.
55581634Sbrian * One of pip or pip6 must be set.
5566059Samurai */
5576059Samuraiint
55881634SbrianPacketCheck(struct bundle *bundle, u_int32_t family,
55981634Sbrian            const unsigned char *packet, int nb, struct filter *filter,
56081634Sbrian            const char *prefix, unsigned *psecs)
5616059Samurai{
562134789Sbrian  char logbuf[200];
56358033Sbrian  static const char *const TcpFlags[] = {
56458033Sbrian    "FIN", "SYN", "RST", "PSH", "ACK", "URG"
56558033Sbrian  };
56681634Sbrian  const struct tcphdr *th;
56781634Sbrian  const struct udphdr *uh;
56881634Sbrian  const struct icmp *icmph;
56981634Sbrian#ifndef NOINET6
57081634Sbrian  const struct icmp6_hdr *icmp6h;
57181634Sbrian#endif
57281634Sbrian  const unsigned char *payload;
57381634Sbrian  struct ncpaddr srcaddr, dstaddr;
574134789Sbrian  int cproto, mask, len, n, pri, logit, result, datalen, frag;
575134789Sbrian  unsigned loglen;
57681634Sbrian  u_char tos;
5776059Samurai
57858776Sbrian  logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
57958776Sbrian          (!filter || filter->logok);
58026692Sbrian  loglen = 0;
58158033Sbrian  pri = 0;
5826059Samurai
58381634Sbrian#ifndef NOINET6
58481634Sbrian  if (family == AF_INET6) {
58581634Sbrian    const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
58681634Sbrian
58781634Sbrian    ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
58881634Sbrian    ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
58981634Sbrian    datalen = ntohs(pip6->ip6_plen);
59081634Sbrian    payload = packet + sizeof *pip6;
59181634Sbrian    cproto = pip6->ip6_nxt;
59281738Sbrian    tos = 0;					/* XXX: pip6->ip6_vfc >> 4 ? */
59381634Sbrian    frag = 0;					/* XXX: ??? */
59481634Sbrian  } else
59581634Sbrian#endif
59681634Sbrian  {
59781634Sbrian    const struct ip *pip = (const struct ip *)packet;
59881634Sbrian
59981634Sbrian    ncpaddr_setip4(&srcaddr, pip->ip_src);
60081634Sbrian    ncpaddr_setip4(&dstaddr, pip->ip_dst);
60181634Sbrian    datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
60281634Sbrian    payload = packet + (pip->ip_hl << 2);
60381634Sbrian    cproto = pip->ip_p;
60481634Sbrian    tos = pip->ip_tos;
60581634Sbrian    frag = ntohs(pip->ip_off) & IP_OFFMASK;
60681634Sbrian  }
60781634Sbrian
60858033Sbrian  uh = NULL;
6098857Srgrimes
61026692Sbrian  if (logit && loglen < sizeof logbuf) {
61162778Sbrian    if (prefix)
61262778Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix);
61362778Sbrian    else if (filter)
61458776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
61558776Sbrian    else
61658776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
61728679Sbrian    loglen += strlen(logbuf + loglen);
61826692Sbrian  }
6196059Samurai
62081634Sbrian  switch (cproto) {
6216059Samurai  case IPPROTO_ICMP:
62226692Sbrian    if (logit && loglen < sizeof logbuf) {
62381634Sbrian      len = datalen - sizeof *icmph;
62481634Sbrian      icmph = (const struct icmp *)payload;
62528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
62681634Sbrian               "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmph->icmp_type);
62728679Sbrian      loglen += strlen(logbuf + loglen);
62828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
62981634Sbrian               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
63028679Sbrian      loglen += strlen(logbuf + loglen);
6316059Samurai    }
6326059Samurai    break;
63351048Sbrian
63481634Sbrian#ifndef NOINET6
63581634Sbrian  case IPPROTO_ICMPV6:
63681634Sbrian    if (logit && loglen < sizeof logbuf) {
63781634Sbrian      len = datalen - sizeof *icmp6h;
63881634Sbrian      icmp6h = (const struct icmp6_hdr *)payload;
63981634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
64081634Sbrian               "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmp6h->icmp6_type);
64181634Sbrian      loglen += strlen(logbuf + loglen);
64281634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
64381634Sbrian               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
64481634Sbrian      loglen += strlen(logbuf + loglen);
64581634Sbrian    }
64681634Sbrian    break;
64781634Sbrian#endif
64881634Sbrian
6496059Samurai  case IPPROTO_UDP:
65081634Sbrian    uh = (const struct udphdr *)payload;
65181634Sbrian    if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
65251048Sbrian      pri++;
65351048Sbrian
65481634Sbrian    if (!frag && ncp_IsUrgentUdpPort(&bundle->ncp, ntohs(uh->uh_sport),
65581634Sbrian                                     ntohs(uh->uh_dport)))
65651048Sbrian      pri++;
65751048Sbrian
65826692Sbrian    if (logit && loglen < sizeof logbuf) {
65981634Sbrian      len = datalen - sizeof *uh;
66028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
66181634Sbrian               "UDP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(uh->uh_sport));
66228679Sbrian      loglen += strlen(logbuf + loglen);
66328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
66481634Sbrian               "%s:%d (%d/%d)", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport),
66562977Sbrian               len, nb);
66628679Sbrian      loglen += strlen(logbuf + loglen);
6676059Samurai    }
66862778Sbrian
66962778Sbrian    if (Enabled(bundle, OPT_FILTERDECAP) &&
67081634Sbrian        payload[sizeof *uh] == HDLC_ADDR &&
67181634Sbrian        payload[sizeof *uh + 1] == HDLC_UI) {
67262778Sbrian      u_short proto;
67362778Sbrian      const char *type;
67462778Sbrian
67581634Sbrian      memcpy(&proto, payload + sizeof *uh + 2, sizeof proto);
67662778Sbrian      type = NULL;
67762778Sbrian
67862778Sbrian      switch (ntohs(proto)) {
67962778Sbrian        case PROTO_IP:
68062778Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
68181634Sbrian          result = PacketCheck(bundle, AF_INET, payload + sizeof *uh + 4,
68281634Sbrian                               nb - (payload - packet) - sizeof *uh - 4, filter,
68362977Sbrian                               logbuf, psecs);
68462778Sbrian          if (result != -2)
68562778Sbrian              return result;
68662778Sbrian          type = "IP";
68762778Sbrian          break;
68862778Sbrian
68962778Sbrian        case PROTO_VJUNCOMP: type = "compressed VJ";   break;
69062778Sbrian        case PROTO_VJCOMP:   type = "uncompressed VJ"; break;
69162778Sbrian        case PROTO_MP:       type = "Multi-link"; break;
69262778Sbrian        case PROTO_ICOMPD:   type = "Individual link CCP"; break;
69362778Sbrian        case PROTO_COMPD:    type = "CCP"; break;
69462778Sbrian        case PROTO_IPCP:     type = "IPCP"; break;
69562778Sbrian        case PROTO_LCP:      type = "LCP"; break;
69662778Sbrian        case PROTO_PAP:      type = "PAP"; break;
69762778Sbrian        case PROTO_CBCP:     type = "CBCP"; break;
69862778Sbrian        case PROTO_LQR:      type = "LQR"; break;
69962778Sbrian        case PROTO_CHAP:     type = "CHAP"; break;
70062778Sbrian      }
70162778Sbrian      if (type) {
70262778Sbrian        snprintf(logbuf + loglen, sizeof logbuf - loglen,
70362778Sbrian                 " - %s data", type);
70462778Sbrian        loglen += strlen(logbuf + loglen);
70562778Sbrian      }
70662778Sbrian    }
70762778Sbrian
7086059Samurai    break;
70951048Sbrian
71051809Sbrian#ifdef IPPROTO_GRE
71151809Sbrian  case IPPROTO_GRE:
71251809Sbrian    if (logit && loglen < sizeof logbuf) {
71351809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
71481634Sbrian          "GRE: %s ---> ", ncpaddr_ntoa(&srcaddr));
71551809Sbrian      loglen += strlen(logbuf + loglen);
71651809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
71781634Sbrian              "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
71851809Sbrian      loglen += strlen(logbuf + loglen);
71951809Sbrian    }
72051809Sbrian    break;
72151809Sbrian#endif
72251809Sbrian
72349374Sbrian#ifdef IPPROTO_OSPFIGP
72449372Sbrian  case IPPROTO_OSPFIGP:
72549372Sbrian    if (logit && loglen < sizeof logbuf) {
72649372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
72781634Sbrian               "OSPF: %s ---> ", ncpaddr_ntoa(&srcaddr));
72849372Sbrian      loglen += strlen(logbuf + loglen);
72949372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
73081634Sbrian               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
73149372Sbrian      loglen += strlen(logbuf + loglen);
73249372Sbrian    }
73349372Sbrian    break;
73449374Sbrian#endif
73551048Sbrian
73681634Sbrian#ifndef NOINET6
73781634Sbrian  case IPPROTO_IPV6:
73881634Sbrian    if (logit && loglen < sizeof logbuf) {
73981634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
74081634Sbrian               "IPv6: %s ---> ", ncpaddr_ntoa(&srcaddr));
74181634Sbrian      loglen += strlen(logbuf + loglen);
74281634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
74381634Sbrian               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
74481634Sbrian      loglen += strlen(logbuf + loglen);
74581634Sbrian    }
74681634Sbrian
74781634Sbrian    if (Enabled(bundle, OPT_FILTERDECAP)) {
74881634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
74981634Sbrian      result = PacketCheck(bundle, AF_INET6, payload, nb - (payload - packet),
75081634Sbrian                           filter, logbuf, psecs);
75181634Sbrian      if (result != -2)
75281634Sbrian        return result;
75381634Sbrian    }
75481634Sbrian    break;
75581634Sbrian#endif
75681634Sbrian
75736961Sbrian  case IPPROTO_IPIP:
75836961Sbrian    if (logit && loglen < sizeof logbuf) {
75936961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
76081634Sbrian               "IPIP: %s ---> ", ncpaddr_ntoa(&srcaddr));
76136961Sbrian      loglen += strlen(logbuf + loglen);
76236961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
76381634Sbrian               "%s", ncpaddr_ntoa(&dstaddr));
76436961Sbrian      loglen += strlen(logbuf + loglen);
76581634Sbrian    }
76675894Sbrian
76781634Sbrian    if (Enabled(bundle, OPT_FILTERDECAP) &&
76881634Sbrian        ((const struct ip *)payload)->ip_v == 4) {
76981634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
77081634Sbrian      result = PacketCheck(bundle, AF_INET, payload, nb - (payload - packet),
77181634Sbrian                           filter, logbuf, psecs);
772134789Sbrian      loglen += strlen(logbuf + loglen);
77381634Sbrian      if (result != -2)
77481634Sbrian        return result;
77536961Sbrian    }
77636961Sbrian    break;
77751048Sbrian
77865846Sbrian  case IPPROTO_ESP:
77965846Sbrian    if (logit && loglen < sizeof logbuf) {
78065846Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
78181634Sbrian               "ESP: %s ---> ", ncpaddr_ntoa(&srcaddr));
78265846Sbrian      loglen += strlen(logbuf + loglen);
78371781Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
78481634Sbrian               ncpaddr_ntoa(&dstaddr), payload);
78565846Sbrian      loglen += strlen(logbuf + loglen);
78665846Sbrian    }
78765846Sbrian    break;
78865846Sbrian
78965846Sbrian  case IPPROTO_AH:
79065846Sbrian    if (logit && loglen < sizeof logbuf) {
79165846Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
79281634Sbrian               "AH: %s ---> ", ncpaddr_ntoa(&srcaddr));
79365846Sbrian      loglen += strlen(logbuf + loglen);
79471781Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
79581634Sbrian               ncpaddr_ntoa(&dstaddr), payload + sizeof(u_int32_t));
79665846Sbrian      loglen += strlen(logbuf + loglen);
79765846Sbrian    }
79865846Sbrian    break;
79965846Sbrian
80036961Sbrian  case IPPROTO_IGMP:
80136961Sbrian    if (logit && loglen < sizeof logbuf) {
80281634Sbrian      uh = (const struct udphdr *)payload;
80336961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
80481634Sbrian               "IGMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr),
80562977Sbrian               ntohs(uh->uh_sport));
80636961Sbrian      loglen += strlen(logbuf + loglen);
80736961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
80881634Sbrian               "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport));
80936961Sbrian      loglen += strlen(logbuf + loglen);
81036961Sbrian    }
81136961Sbrian    break;
81251048Sbrian
8136059Samurai  case IPPROTO_TCP:
81481634Sbrian    th = (const struct tcphdr *)payload;
81581634Sbrian    if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
81650867Sbrian      pri++;
81751048Sbrian
81881634Sbrian    if (!frag && ncp_IsUrgentTcpPort(&bundle->ncp, ntohs(th->th_sport),
81981634Sbrian                                     ntohs(th->th_dport)))
82050867Sbrian      pri++;
82150867Sbrian
82226692Sbrian    if (logit && loglen < sizeof logbuf) {
82381634Sbrian      len = datalen - (th->th_off << 2);
82428679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
82581634Sbrian           "TCP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(th->th_sport));
82628679Sbrian      loglen += strlen(logbuf + loglen);
82728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
82881634Sbrian               "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(th->th_dport));
82928679Sbrian      loglen += strlen(logbuf + loglen);
8306059Samurai      n = 0;
8316059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
83262977Sbrian        if (th->th_flags & mask) {
83362977Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
83462977Sbrian          loglen += strlen(logbuf + loglen);
83562977Sbrian        }
83662977Sbrian        n++;
8376059Samurai      }
83828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
83962977Sbrian               "  seq:%lx  ack:%lx (%d/%d)",
84062977Sbrian               (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
84128679Sbrian      loglen += strlen(logbuf + loglen);
8426059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
84381634Sbrian        const u_short *sp;
8446059Samurai
84581634Sbrian        sp = (const u_short *)(payload + 20);
84662977Sbrian        if (ntohs(sp[0]) == 0x0204) {
84762977Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen,
84862977Sbrian                   " MSS = %d", ntohs(sp[1]));
84962977Sbrian          loglen += strlen(logbuf + loglen);
85062977Sbrian        }
8516059Samurai      }
8526059Samurai    }
8536059Samurai    break;
85462778Sbrian
85562778Sbrian  default:
85662778Sbrian    if (prefix)
85762778Sbrian      return -2;
85881634Sbrian
85981634Sbrian    if (logit && loglen < sizeof logbuf) {
86081634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
86181634Sbrian               "<%d>: %s ---> ", cproto, ncpaddr_ntoa(&srcaddr));
86281634Sbrian      loglen += strlen(logbuf + loglen);
86381634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
86481634Sbrian               "%s (%d)", ncpaddr_ntoa(&dstaddr), nb);
86581634Sbrian      loglen += strlen(logbuf + loglen);
86681634Sbrian    }
86781634Sbrian    break;
8686059Samurai  }
86926692Sbrian
87081634Sbrian  if (filter && FilterCheck(packet, family, filter, psecs)) {
87131142Sbrian    if (logit)
87236285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
87358033Sbrian    result = -1;
8746059Samurai  } else {
87536285Sbrian    /* Check Keep Alive filter */
87658033Sbrian    if (logit && log_IsKept(LogTCPIP)) {
87762977Sbrian      unsigned alivesecs;
87862977Sbrian
87962977Sbrian      alivesecs = 0;
88081634Sbrian      if (filter &&
88181634Sbrian          FilterCheck(packet, family, &bundle->filter.alive, &alivesecs))
88236285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
88362977Sbrian      else if (psecs != NULL) {
88462977Sbrian        if(*psecs == 0)
88562977Sbrian          *psecs = alivesecs;
88662977Sbrian        if (*psecs) {
88762977Sbrian          if (*psecs != alivesecs)
88898243Sbrian            log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n",
88962977Sbrian                       logbuf, *psecs, alivesecs);
89062977Sbrian          else
89162977Sbrian            log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs);
89262977Sbrian        } else
89362977Sbrian          log_Printf(LogTCPIP, "%s\n", logbuf);
89462977Sbrian      }
8956735Samurai    }
89658033Sbrian    result = pri;
8976059Samurai  }
89858033Sbrian
89958776Sbrian  if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
90058033Sbrian    ip_LogDNS(uh, filter->name);
90158033Sbrian
90258033Sbrian  return result;
9036059Samurai}
9046059Samurai
905134789Sbrianstatic size_t
90681634Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp, u_int32_t af)
90736285Sbrian{
908134789Sbrian  ssize_t nw;
909134789Sbrian  size_t nb;
91031343Sbrian  struct tun_data tun;
91156413Sbrian  char *data;
91262977Sbrian  unsigned secs, alivesecs;
9136059Samurai
91454912Sbrian  nb = m_length(bp);
91547168Sbrian  if (nb > sizeof tun.data) {
916134833Smarcel    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %zd, max %d)\n",
91747168Sbrian               l->name, nb, (int)(sizeof tun.data));
91854912Sbrian    m_freem(bp);
91981634Sbrian    return 0;
92047168Sbrian  }
92146686Sbrian  mbuf_Read(bp, tun.data, nb);
92226031Sbrian
92362977Sbrian  secs = 0;
92481634Sbrian  if (PacketCheck(bundle, af, tun.data, nb, &bundle->filter.in,
92581634Sbrian                  NULL, &secs) < 0)
92681634Sbrian    return 0;
92726031Sbrian
92862977Sbrian  alivesecs = 0;
92981634Sbrian  if (!FilterCheck(tun.data, af, &bundle->filter.alive, &alivesecs)) {
93062977Sbrian    if (secs == 0)
93162977Sbrian      secs = alivesecs;
93262977Sbrian    bundle_StartIdleTimer(bundle, secs);
93362977Sbrian  }
93426031Sbrian
93556413Sbrian  if (bundle->dev.header) {
93681634Sbrian    tun.header.family = htonl(af);
93756413Sbrian    nb += sizeof tun - sizeof tun.data;
93856413Sbrian    data = (char *)&tun;
93956413Sbrian  } else
94056413Sbrian    data = tun.data;
94156413Sbrian
94256413Sbrian  nw = write(bundle->dev.fd, data, nb);
943134789Sbrian  if (nw != (ssize_t)nb) {
94446686Sbrian    if (nw == -1)
945134833Smarcel      log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %s\n",
94647168Sbrian                 l->name, nb, strerror(errno));
94746686Sbrian    else
948134833Smarcel      log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %zd\n", l->name, nb,
949134833Smarcel	  nw);
95046686Sbrian  }
95136285Sbrian
95281634Sbrian  return nb;
9536059Samurai}
9546059Samurai
95581634Sbrianstruct mbuf *
95681634Sbrianipv4_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
9576059Samurai{
95881634Sbrian  int nb;
9596059Samurai
96081634Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
96181634Sbrian    log_Printf(LogWARN, "ipv4_Input: IPCP not open - packet dropped\n");
96281634Sbrian    m_freem(bp);
96381634Sbrian    return NULL;
96438557Sbrian  }
9656059Samurai
96681634Sbrian  m_settype(bp, MB_IPIN);
96738544Sbrian
96881634Sbrian  nb = ip_Input(bundle, l, bp, AF_INET);
96981634Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
97038544Sbrian
97181634Sbrian  return NULL;
9727001Samurai}
9737001Samurai
97481634Sbrian#ifndef NOINET6
97581634Sbrianstruct mbuf *
97681634Sbrianipv6_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
9776059Samurai{
97881634Sbrian  int nb;
9796059Samurai
98081897Sbrian  if (bundle->ncp.ipv6cp.fsm.state != ST_OPENED) {
98181634Sbrian    log_Printf(LogWARN, "ipv6_Input: IPV6CP not open - packet dropped\n");
98281634Sbrian    m_freem(bp);
98381634Sbrian    return NULL;
98478411Sbrian  }
98578411Sbrian
98681634Sbrian  m_settype(bp, MB_IPV6IN);
98736285Sbrian
98881634Sbrian  nb = ip_Input(bundle, l, bp, AF_INET6);
98981634Sbrian  ipv6cp_AddInOctets(&bundle->ncp.ipv6cp, nb);
99081634Sbrian
99181634Sbrian  return NULL;
9926059Samurai}
99381634Sbrian#endif
994