ip.c revision 129175
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: head/usr.sbin/ppp/ip.c 129175 2004-05-13 09:03:00Z dds $
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  };
11358033Sbrian  int 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  };
14058033Sbrian  int 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
20981634SbrianFilterCheck(const unsigned char *packet, u_int32_t family,
21081634Sbrian            const struct filter *filter, unsigned *psecs)
2116059Samurai{
21249140Sbrian  int gotinfo;			/* true if IP payload decoded */
21381634Sbrian  int cproto;			/* IPPROTO_* protocol number if (gotinfo) */
21449140Sbrian  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
21549140Sbrian  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
21649140Sbrian  int n;			/* filter rule to process */
21749140Sbrian  int len;			/* bytes used in dbuff */
21849140Sbrian  int didname;			/* true if filter header printed */
21949140Sbrian  int match;			/* true if condition matched */
22081634Sbrian  int mindata;			/* minimum data size or zero */
22149140Sbrian  const struct filterent *fp = filter->rule;
222129175Sdds  char dbuff[100], dstip[16];
22381634Sbrian  struct ncpaddr srcaddr, dstaddr;
22481634Sbrian  const char *payload;		/* IP payload */
22581634Sbrian  int datalen;			/* IP datagram length */
2266059Samurai
22749140Sbrian  if (fp->f_action == A_NONE)
22862977Sbrian    return 0;		/* No rule is given. Permit this packet */
22936285Sbrian
23081634Sbrian#ifndef NOINET6
23181634Sbrian  if (family == AF_INET6) {
23281634Sbrian    const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
23381634Sbrian
23481634Sbrian    ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
23581634Sbrian    ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
23681738Sbrian    datalen = ntohs(pip6->ip6_plen);
23781738Sbrian    payload = packet + sizeof *pip6;
23881634Sbrian    cproto = pip6->ip6_nxt;
23981634Sbrian  } else
24081634Sbrian#endif
24181634Sbrian  {
24281634Sbrian    /*
24381634Sbrian     * Deny any packet fragment that tries to over-write the header.
24481634Sbrian     * Since we no longer have the real header available, punt on the
24581634Sbrian     * largest normal header - 20 bytes for TCP without options, rounded
24681634Sbrian     * up to the next possible fragment boundary.  Since the smallest
24781634Sbrian     * `legal' MTU is 576, and the smallest recommended MTU is 296, any
24881634Sbrian     * fragmentation within this range is dubious at best
24981634Sbrian     */
25081634Sbrian    const struct ip *pip = (const struct ip *)packet;
25181634Sbrian
25298243Sbrian    len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
25381634Sbrian    if (len > 0) {		/* Not first fragment within datagram */
25481634Sbrian      if (len < (24 >> 3)) {	/* don't allow fragment to over-write header */
25581634Sbrian        log_Printf(LogFILTER, " error: illegal header\n");
25681634Sbrian        return 1;
25781634Sbrian      }
25881634Sbrian      /* permit fragments on in and out filter */
25981634Sbrian      if (!filter->fragok) {
26081634Sbrian        log_Printf(LogFILTER, " error: illegal fragmentation\n");
26181634Sbrian        return 1;
26281634Sbrian      } else
26381634Sbrian        return 0;
26465181Sbrian    }
26598243Sbrian
26681634Sbrian    ncpaddr_setip4(&srcaddr, pip->ip_src);
26781634Sbrian    ncpaddr_setip4(&dstaddr, pip->ip_dst);
26881634Sbrian    datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
26981634Sbrian    payload = packet + (pip->ip_hl << 2);
27081634Sbrian    cproto = pip->ip_p;
27149140Sbrian  }
27281634Sbrian
273129175Sdds
27481634Sbrian  gotinfo = estab = syn = finrst = didname = 0;
27549140Sbrian  sport = dport = 0;
27681634Sbrian
27749140Sbrian  for (n = 0; n < MAXFILTERS; ) {
27849140Sbrian    if (fp->f_action == A_NONE) {
27949140Sbrian      n++;
28049140Sbrian      fp++;
28149140Sbrian      continue;
28249140Sbrian    }
28336285Sbrian
28449140Sbrian    if (!didname) {
28549140Sbrian      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
28649140Sbrian      didname = 1;
28749140Sbrian    }
2886059Samurai
28949140Sbrian    match = 0;
29081634Sbrian
29181634Sbrian    if ((ncprange_family(&fp->f_src) == AF_UNSPEC ||
29281634Sbrian         ncprange_contains(&fp->f_src, &srcaddr)) &&
29381634Sbrian        (ncprange_family(&fp->f_dst) == AF_UNSPEC ||
29481634Sbrian         ncprange_contains(&fp->f_dst, &dstaddr))) {
29581634Sbrian      if (fp->f_proto != 0) {
29662977Sbrian        if (!gotinfo) {
29762977Sbrian          const struct tcphdr *th;
29862977Sbrian          const struct udphdr *uh;
29962977Sbrian          const struct icmp *ih;
30081634Sbrian#ifndef NOINET6
30181634Sbrian          const struct icmp6_hdr *ih6;
30281634Sbrian#endif
30381634Sbrian          mindata = 0;
30481634Sbrian          sport = dport = 0;
30581634Sbrian          estab = syn = finrst = -1;
30649140Sbrian
30781634Sbrian          switch (cproto) {
30862977Sbrian          case IPPROTO_ICMP:
30981634Sbrian            mindata = 8;	/* ICMP must be at least 8 octets */
31081634Sbrian            ih = (const struct icmp *)payload;
311112660Sbrian            sport = ih->icmp_type;
31281634Sbrian            if (log_IsKept(LogDEBUG))
31381634Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
31481634Sbrian            break;
31565181Sbrian
31681634Sbrian#ifndef NOINET6
31781634Sbrian          case IPPROTO_ICMPV6:
31881634Sbrian            mindata = 8;	/* ICMP must be at least 8 octets */
31981634Sbrian            ih6 = (const struct icmp6_hdr *)payload;
320112660Sbrian            sport = ih6->icmp6_type;
32162977Sbrian            if (log_IsKept(LogDEBUG))
32262977Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
32362977Sbrian            break;
32481634Sbrian#endif
32581634Sbrian
32662977Sbrian          case IPPROTO_IGMP:
32781634Sbrian            mindata = 8;	/* IGMP uses 8-octet messages */
32862977Sbrian            break;
32981634Sbrian
33051809Sbrian#ifdef IPPROTO_GRE
33151809Sbrian          case IPPROTO_GRE:
33281634Sbrian            mindata = 2;	/* GRE uses 2-octet+ messages */
33351809Sbrian            break;
33451809Sbrian#endif
33549374Sbrian#ifdef IPPROTO_OSPFIGP
33662977Sbrian          case IPPROTO_OSPFIGP:
33781634Sbrian            mindata = 8;	/* IGMP uses 8-octet messages */
33862977Sbrian            break;
33949374Sbrian#endif
34081634Sbrian#ifndef NOINET6
34181634Sbrian          case IPPROTO_IPV6:
34281634Sbrian            mindata = 20;	/* RFC2893 Section 3.5: 5 * 32bit words */
34365846Sbrian            break;
34481634Sbrian#endif
34581634Sbrian
34662977Sbrian          case IPPROTO_UDP:
34781634Sbrian            mindata = 8;	/* UDP header is 8 octets */
34881634Sbrian            uh = (const struct udphdr *)payload;
34962977Sbrian            sport = ntohs(uh->uh_sport);
35062977Sbrian            dport = ntohs(uh->uh_dport);
35162977Sbrian            if (log_IsKept(LogDEBUG))
35262977Sbrian              snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
35362977Sbrian                       sport, dport);
35462977Sbrian            break;
35581634Sbrian
35662977Sbrian          case IPPROTO_TCP:
35781634Sbrian            th = (const struct tcphdr *)payload;
35881634Sbrian            /*
35981634Sbrian             * TCP headers are variable length.  The following code
36062977Sbrian             * ensures that the TCP header length isn't de-referenced if
36162977Sbrian             * the datagram is too short
36262977Sbrian             */
36365181Sbrian            if (datalen < 20 || datalen < (th->th_off << 2)) {
36465181Sbrian              log_Printf(LogFILTER, " error: TCP header incorrect\n");
36562977Sbrian              return 1;
36665181Sbrian            }
36762977Sbrian            sport = ntohs(th->th_sport);
36862977Sbrian            dport = ntohs(th->th_dport);
36962977Sbrian            estab = (th->th_flags & TH_ACK);
37062977Sbrian            syn = (th->th_flags & TH_SYN);
37162977Sbrian            finrst = (th->th_flags & (TH_FIN|TH_RST));
37262977Sbrian            if (log_IsKept(LogDEBUG)) {
37362977Sbrian              if (!estab)
37462977Sbrian                snprintf(dbuff, sizeof dbuff,
37562977Sbrian                         "flags = %02x, sport = %d, dport = %d",
37662977Sbrian                         th->th_flags, sport, dport);
37762977Sbrian              else
37862977Sbrian                *dbuff = '\0';
37962977Sbrian            }
38062977Sbrian            break;
38162977Sbrian          default:
38281634Sbrian            break;
38362977Sbrian          }
38426516Sbrian
38581634Sbrian          if (datalen < mindata) {
38681634Sbrian            log_Printf(LogFILTER, " error: proto %s must be at least"
387129175Sdds                       " %d octets\n", prototxt(cproto), mindata);
38881634Sbrian            return 1;
38981634Sbrian          }
39081634Sbrian
39162977Sbrian          if (log_IsKept(LogDEBUG)) {
39262977Sbrian            if (estab != -1) {
39362977Sbrian              len = strlen(dbuff);
39462977Sbrian              snprintf(dbuff + len, sizeof dbuff - len,
39562977Sbrian                       ", estab = %d, syn = %d, finrst = %d",
39662977Sbrian                       estab, syn, finrst);
39762977Sbrian            }
398129175Sdds            log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
399129175Sdds                       prototxt(cproto), dbuff);
40062977Sbrian          }
40162977Sbrian          gotinfo = 1;
40262977Sbrian        }
40381634Sbrian
40462977Sbrian        if (log_IsKept(LogDEBUG)) {
40562977Sbrian          if (fp->f_srcop != OP_NONE) {
40662977Sbrian            snprintf(dbuff, sizeof dbuff, ", src %s %d",
40762977Sbrian                     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
40862977Sbrian            len = strlen(dbuff);
40962977Sbrian          } else
41062977Sbrian            len = 0;
41162977Sbrian          if (fp->f_dstop != OP_NONE) {
41262977Sbrian            snprintf(dbuff + len, sizeof dbuff - len,
41362977Sbrian                     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
41462977Sbrian                     fp->f_dstport);
41562977Sbrian          } else if (!len)
41662977Sbrian            *dbuff = '\0';
41749140Sbrian
41862977Sbrian          log_Printf(LogDEBUG, "  rule = %d: Address match, "
41981634Sbrian                     "check against proto %d%s, action = %s\n",
42081634Sbrian                     n, fp->f_proto, dbuff, filter_Action2Nam(fp->f_action));
42162977Sbrian        }
42249140Sbrian
42362977Sbrian        if (cproto == fp->f_proto) {
42462977Sbrian          if ((fp->f_srcop == OP_NONE ||
42562977Sbrian               PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
42662977Sbrian              (fp->f_dstop == OP_NONE ||
42762977Sbrian               PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
42862977Sbrian              (fp->f_estab == 0 || estab) &&
42962977Sbrian              (fp->f_syn == 0 || syn) &&
43062977Sbrian              (fp->f_finrst == 0 || finrst)) {
43162977Sbrian            match = 1;
43262977Sbrian          }
43362977Sbrian        }
43449140Sbrian      } else {
43562977Sbrian        /* Address is matched and no protocol specified. Make a decision. */
43662977Sbrian        log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
43762977Sbrian                   filter_Action2Nam(fp->f_action));
43862977Sbrian        match = 1;
4396059Samurai      }
44049140Sbrian    } else
44149140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
44249140Sbrian
44349140Sbrian    if (match != fp->f_invert) {
44449140Sbrian      /* Take specified action */
44549140Sbrian      if (fp->f_action < A_NONE)
44662977Sbrian        fp = &filter->rule[n = fp->f_action];
44765181Sbrian      else {
44862977Sbrian        if (fp->f_action == A_PERMIT) {
44962977Sbrian          if (psecs != NULL)
45062977Sbrian            *psecs = fp->timeout;
45165181Sbrian          if (strcmp(filter->name, "DIAL") == 0) {
45265181Sbrian            /* If dial filter then even print out accept packets */
45365181Sbrian            if (log_IsKept(LogFILTER)) {
45481634Sbrian              snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
45565181Sbrian              log_Printf(LogFILTER, "%sbound rule = %d accept %s "
456129175Sdds                         "src = %s:%d dst = %s:%d\n", filter->name, n,
457129175Sdds                         prototxt(cproto), ncpaddr_ntoa(&srcaddr), sport,
458129175Sdds                         dstip, dport);
45965181Sbrian            }
46065181Sbrian          }
46162977Sbrian          return 0;
46265181Sbrian        } else {
46365181Sbrian          if (log_IsKept(LogFILTER)) {
46481634Sbrian            snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
46598243Sbrian            log_Printf(LogFILTER,
46698243Sbrian                       "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n",
467129175Sdds                       filter->name, n, prototxt(cproto),
46881634Sbrian                       ncpaddr_ntoa(&srcaddr), sport, dstip, dport);
46965181Sbrian          }
47098243Sbrian          return 1;
47181634Sbrian        }		/* Explict match.  Deny this packet */
47265181Sbrian      }
47349140Sbrian    } else {
47449140Sbrian      n++;
4756059Samurai      fp++;
4766059Samurai    }
4776059Samurai  }
47865181Sbrian
47965181Sbrian  if (log_IsKept(LogFILTER)) {
48081634Sbrian    snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr));
48198243Sbrian    log_Printf(LogFILTER,
48298243Sbrian               "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n",
483129175Sdds               filter->name, prototxt(cproto), ncpaddr_ntoa(&srcaddr),
484129175Sdds               sport, dstip, dport);
48565181Sbrian  }
48665181Sbrian
48781634Sbrian  return 1;		/* No rule matched, deny this packet */
4886059Samurai}
4896059Samurai
4906059Samuraistatic void
49158033Sbrianip_LogDNS(const struct udphdr *uh, const char *direction)
49258033Sbrian{
49358033Sbrian  struct dns_header header;
49458033Sbrian  const u_short *pktptr;
49558033Sbrian  const u_char *ptr;
49677487Sbrian  u_short *hptr, tmp;
49758033Sbrian  int len;
49858033Sbrian
49958033Sbrian  ptr = (const char *)uh + sizeof *uh;
50058033Sbrian  len = ntohs(uh->uh_ulen) - sizeof *uh;
50158033Sbrian  if (len < sizeof header + 5)		/* rfc1024 */
50258033Sbrian    return;
50358033Sbrian
50458033Sbrian  pktptr = (const u_short *)ptr;
50558033Sbrian  hptr = (u_short *)&header;
50658033Sbrian  ptr += sizeof header;
50758033Sbrian  len -= sizeof header;
50858033Sbrian
50958033Sbrian  while (pktptr < (const u_short *)ptr) {
51062977Sbrian    *hptr++ = ntohs(*pktptr);		/* Careful of macro side-effects ! */
51158033Sbrian    pktptr++;
51258033Sbrian  }
51358033Sbrian
51458033Sbrian  if (header.opcode == OPCODE_QUERY && header.qr == 0) {
51558033Sbrian    /* rfc1035 */
51674049Sbrian    char namewithdot[MAXHOSTNAMELEN + 1], *n;
51758033Sbrian    const char *qtype, *qclass;
51858033Sbrian    const u_char *end;
51958033Sbrian
52074049Sbrian    n = namewithdot;
52158033Sbrian    end = ptr + len - 4;
52274049Sbrian    if (end - ptr >= sizeof namewithdot)
52374049Sbrian      end = ptr + sizeof namewithdot - 1;
52458033Sbrian    while (ptr < end) {
52558033Sbrian      len = *ptr++;
52658033Sbrian      if (len > end - ptr)
52758033Sbrian        len = end - ptr;
52874049Sbrian      if (n != namewithdot)
52958033Sbrian        *n++ = '.';
53058033Sbrian      memcpy(n, ptr, len);
53158033Sbrian      ptr += len;
53258033Sbrian      n += len;
53358033Sbrian    }
53458033Sbrian    *n = '\0';
53558033Sbrian
53677487Sbrian    if (log_IsKept(LogDNS)) {
53777487Sbrian      memcpy(&tmp, end, sizeof tmp);
53877487Sbrian      qtype = dns_Qtype2Txt(ntohs(tmp));
53977487Sbrian      memcpy(&tmp, end + 2, sizeof tmp);
54077487Sbrian      qclass = dns_Qclass2Txt(ntohs(tmp));
54177487Sbrian
54277487Sbrian      log_Printf(LogDNS, "%sbound query %s %s %s\n",
54377487Sbrian                 direction, qclass, qtype, namewithdot);
54477487Sbrian    }
54558033Sbrian  }
54658033Sbrian}
54758033Sbrian
5486059Samurai/*
54981634Sbrian * Check if the given packet matches the given filter.
55081634Sbrian * One of pip or pip6 must be set.
5516059Samurai */
5526059Samuraiint
55381634SbrianPacketCheck(struct bundle *bundle, u_int32_t family,
55481634Sbrian            const unsigned char *packet, int nb, struct filter *filter,
55581634Sbrian            const char *prefix, unsigned *psecs)
5566059Samurai{
55758033Sbrian  static const char *const TcpFlags[] = {
55858033Sbrian    "FIN", "SYN", "RST", "PSH", "ACK", "URG"
55958033Sbrian  };
56081634Sbrian  const struct tcphdr *th;
56181634Sbrian  const struct udphdr *uh;
56281634Sbrian  const struct icmp *icmph;
56381634Sbrian#ifndef NOINET6
56481634Sbrian  const struct icmp6_hdr *icmp6h;
56581634Sbrian#endif
56681634Sbrian  const unsigned char *payload;
56781634Sbrian  struct ncpaddr srcaddr, dstaddr;
56881634Sbrian  int cproto, mask, len, n, pri, logit, loglen, result;
56937010Sbrian  char logbuf[200];
57081634Sbrian  int datalen, frag;
57181634Sbrian  u_char tos;
5726059Samurai
57358776Sbrian  logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
57458776Sbrian          (!filter || filter->logok);
57526692Sbrian  loglen = 0;
57658033Sbrian  pri = 0;
5776059Samurai
57881634Sbrian#ifndef NOINET6
57981634Sbrian  if (family == AF_INET6) {
58081634Sbrian    const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet;
58181634Sbrian
58281634Sbrian    ncpaddr_setip6(&srcaddr, &pip6->ip6_src);
58381634Sbrian    ncpaddr_setip6(&dstaddr, &pip6->ip6_dst);
58481634Sbrian    datalen = ntohs(pip6->ip6_plen);
58581634Sbrian    payload = packet + sizeof *pip6;
58681634Sbrian    cproto = pip6->ip6_nxt;
58781738Sbrian    tos = 0;					/* XXX: pip6->ip6_vfc >> 4 ? */
58881634Sbrian    frag = 0;					/* XXX: ??? */
58981634Sbrian  } else
59081634Sbrian#endif
59181634Sbrian  {
59281634Sbrian    const struct ip *pip = (const struct ip *)packet;
59381634Sbrian
59481634Sbrian    ncpaddr_setip4(&srcaddr, pip->ip_src);
59581634Sbrian    ncpaddr_setip4(&dstaddr, pip->ip_dst);
59681634Sbrian    datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
59781634Sbrian    payload = packet + (pip->ip_hl << 2);
59881634Sbrian    cproto = pip->ip_p;
59981634Sbrian    tos = pip->ip_tos;
60081634Sbrian    frag = ntohs(pip->ip_off) & IP_OFFMASK;
60181634Sbrian  }
60281634Sbrian
60358033Sbrian  uh = NULL;
6048857Srgrimes
60526692Sbrian  if (logit && loglen < sizeof logbuf) {
60662778Sbrian    if (prefix)
60762778Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix);
60862778Sbrian    else if (filter)
60958776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
61058776Sbrian    else
61158776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
61228679Sbrian    loglen += strlen(logbuf + loglen);
61326692Sbrian  }
6146059Samurai
61581634Sbrian  switch (cproto) {
6166059Samurai  case IPPROTO_ICMP:
61726692Sbrian    if (logit && loglen < sizeof logbuf) {
61881634Sbrian      len = datalen - sizeof *icmph;
61981634Sbrian      icmph = (const struct icmp *)payload;
62028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
62181634Sbrian               "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmph->icmp_type);
62228679Sbrian      loglen += strlen(logbuf + loglen);
62328679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
62481634Sbrian               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
62528679Sbrian      loglen += strlen(logbuf + loglen);
6266059Samurai    }
6276059Samurai    break;
62851048Sbrian
62981634Sbrian#ifndef NOINET6
63081634Sbrian  case IPPROTO_ICMPV6:
63181634Sbrian    if (logit && loglen < sizeof logbuf) {
63281634Sbrian      len = datalen - sizeof *icmp6h;
63381634Sbrian      icmp6h = (const struct icmp6_hdr *)payload;
63481634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
63581634Sbrian               "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmp6h->icmp6_type);
63681634Sbrian      loglen += strlen(logbuf + loglen);
63781634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
63881634Sbrian               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb);
63981634Sbrian      loglen += strlen(logbuf + loglen);
64081634Sbrian    }
64181634Sbrian    break;
64281634Sbrian#endif
64381634Sbrian
6446059Samurai  case IPPROTO_UDP:
64581634Sbrian    uh = (const struct udphdr *)payload;
64681634Sbrian    if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
64751048Sbrian      pri++;
64851048Sbrian
64981634Sbrian    if (!frag && ncp_IsUrgentUdpPort(&bundle->ncp, ntohs(uh->uh_sport),
65081634Sbrian                                     ntohs(uh->uh_dport)))
65151048Sbrian      pri++;
65251048Sbrian
65326692Sbrian    if (logit && loglen < sizeof logbuf) {
65481634Sbrian      len = datalen - sizeof *uh;
65528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
65681634Sbrian               "UDP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(uh->uh_sport));
65728679Sbrian      loglen += strlen(logbuf + loglen);
65828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
65981634Sbrian               "%s:%d (%d/%d)", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport),
66062977Sbrian               len, nb);
66128679Sbrian      loglen += strlen(logbuf + loglen);
6626059Samurai    }
66362778Sbrian
66462778Sbrian    if (Enabled(bundle, OPT_FILTERDECAP) &&
66581634Sbrian        payload[sizeof *uh] == HDLC_ADDR &&
66681634Sbrian        payload[sizeof *uh + 1] == HDLC_UI) {
66762778Sbrian      u_short proto;
66862778Sbrian      const char *type;
66962778Sbrian
67081634Sbrian      memcpy(&proto, payload + sizeof *uh + 2, sizeof proto);
67162778Sbrian      type = NULL;
67262778Sbrian
67362778Sbrian      switch (ntohs(proto)) {
67462778Sbrian        case PROTO_IP:
67562778Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
67681634Sbrian          result = PacketCheck(bundle, AF_INET, payload + sizeof *uh + 4,
67781634Sbrian                               nb - (payload - packet) - sizeof *uh - 4, filter,
67862977Sbrian                               logbuf, psecs);
67962778Sbrian          if (result != -2)
68062778Sbrian              return result;
68162778Sbrian          type = "IP";
68262778Sbrian          break;
68362778Sbrian
68462778Sbrian        case PROTO_VJUNCOMP: type = "compressed VJ";   break;
68562778Sbrian        case PROTO_VJCOMP:   type = "uncompressed VJ"; break;
68662778Sbrian        case PROTO_MP:       type = "Multi-link"; break;
68762778Sbrian        case PROTO_ICOMPD:   type = "Individual link CCP"; break;
68862778Sbrian        case PROTO_COMPD:    type = "CCP"; break;
68962778Sbrian        case PROTO_IPCP:     type = "IPCP"; break;
69062778Sbrian        case PROTO_LCP:      type = "LCP"; break;
69162778Sbrian        case PROTO_PAP:      type = "PAP"; break;
69262778Sbrian        case PROTO_CBCP:     type = "CBCP"; break;
69362778Sbrian        case PROTO_LQR:      type = "LQR"; break;
69462778Sbrian        case PROTO_CHAP:     type = "CHAP"; break;
69562778Sbrian      }
69662778Sbrian      if (type) {
69762778Sbrian        snprintf(logbuf + loglen, sizeof logbuf - loglen,
69862778Sbrian                 " - %s data", type);
69962778Sbrian        loglen += strlen(logbuf + loglen);
70062778Sbrian      }
70162778Sbrian    }
70262778Sbrian
7036059Samurai    break;
70451048Sbrian
70551809Sbrian#ifdef IPPROTO_GRE
70651809Sbrian  case IPPROTO_GRE:
70751809Sbrian    if (logit && loglen < sizeof logbuf) {
70851809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
70981634Sbrian          "GRE: %s ---> ", ncpaddr_ntoa(&srcaddr));
71051809Sbrian      loglen += strlen(logbuf + loglen);
71151809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
71281634Sbrian              "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
71351809Sbrian      loglen += strlen(logbuf + loglen);
71451809Sbrian    }
71551809Sbrian    break;
71651809Sbrian#endif
71751809Sbrian
71849374Sbrian#ifdef IPPROTO_OSPFIGP
71949372Sbrian  case IPPROTO_OSPFIGP:
72049372Sbrian    if (logit && loglen < sizeof logbuf) {
72149372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
72281634Sbrian               "OSPF: %s ---> ", ncpaddr_ntoa(&srcaddr));
72349372Sbrian      loglen += strlen(logbuf + loglen);
72449372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
72581634Sbrian               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
72649372Sbrian      loglen += strlen(logbuf + loglen);
72749372Sbrian    }
72849372Sbrian    break;
72949374Sbrian#endif
73051048Sbrian
73181634Sbrian#ifndef NOINET6
73281634Sbrian  case IPPROTO_IPV6:
73381634Sbrian    if (logit && loglen < sizeof logbuf) {
73481634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
73581634Sbrian               "IPv6: %s ---> ", ncpaddr_ntoa(&srcaddr));
73681634Sbrian      loglen += strlen(logbuf + loglen);
73781634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
73881634Sbrian               "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb);
73981634Sbrian      loglen += strlen(logbuf + loglen);
74081634Sbrian    }
74181634Sbrian
74281634Sbrian    if (Enabled(bundle, OPT_FILTERDECAP)) {
74381634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
74481634Sbrian      result = PacketCheck(bundle, AF_INET6, payload, nb - (payload - packet),
74581634Sbrian                           filter, logbuf, psecs);
74681634Sbrian      if (result != -2)
74781634Sbrian        return result;
74881634Sbrian    }
74981634Sbrian    break;
75081634Sbrian#endif
75181634Sbrian
75236961Sbrian  case IPPROTO_IPIP:
75336961Sbrian    if (logit && loglen < sizeof logbuf) {
75436961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
75581634Sbrian               "IPIP: %s ---> ", ncpaddr_ntoa(&srcaddr));
75636961Sbrian      loglen += strlen(logbuf + loglen);
75736961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
75881634Sbrian               "%s", ncpaddr_ntoa(&dstaddr));
75936961Sbrian      loglen += strlen(logbuf + loglen);
76081634Sbrian    }
76175894Sbrian
76281634Sbrian    if (Enabled(bundle, OPT_FILTERDECAP) &&
76381634Sbrian        ((const struct ip *)payload)->ip_v == 4) {
76481634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains ");
76581634Sbrian      result = PacketCheck(bundle, AF_INET, payload, nb - (payload - packet),
76681634Sbrian                           filter, logbuf, psecs);
76781634Sbrian      if (result != -2)
76881634Sbrian        return result;
76936961Sbrian    }
77036961Sbrian    break;
77151048Sbrian
77265846Sbrian  case IPPROTO_ESP:
77365846Sbrian    if (logit && loglen < sizeof logbuf) {
77465846Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
77581634Sbrian               "ESP: %s ---> ", ncpaddr_ntoa(&srcaddr));
77665846Sbrian      loglen += strlen(logbuf + loglen);
77771781Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
77881634Sbrian               ncpaddr_ntoa(&dstaddr), payload);
77965846Sbrian      loglen += strlen(logbuf + loglen);
78065846Sbrian    }
78165846Sbrian    break;
78265846Sbrian
78365846Sbrian  case IPPROTO_AH:
78465846Sbrian    if (logit && loglen < sizeof logbuf) {
78565846Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
78681634Sbrian               "AH: %s ---> ", ncpaddr_ntoa(&srcaddr));
78765846Sbrian      loglen += strlen(logbuf + loglen);
78871781Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p",
78981634Sbrian               ncpaddr_ntoa(&dstaddr), payload + sizeof(u_int32_t));
79065846Sbrian      loglen += strlen(logbuf + loglen);
79165846Sbrian    }
79265846Sbrian    break;
79365846Sbrian
79436961Sbrian  case IPPROTO_IGMP:
79536961Sbrian    if (logit && loglen < sizeof logbuf) {
79681634Sbrian      uh = (const struct udphdr *)payload;
79736961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
79881634Sbrian               "IGMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr),
79962977Sbrian               ntohs(uh->uh_sport));
80036961Sbrian      loglen += strlen(logbuf + loglen);
80136961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
80281634Sbrian               "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport));
80336961Sbrian      loglen += strlen(logbuf + loglen);
80436961Sbrian    }
80536961Sbrian    break;
80651048Sbrian
8076059Samurai  case IPPROTO_TCP:
80881634Sbrian    th = (const struct tcphdr *)payload;
80981634Sbrian    if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos)
81050867Sbrian      pri++;
81151048Sbrian
81281634Sbrian    if (!frag && ncp_IsUrgentTcpPort(&bundle->ncp, ntohs(th->th_sport),
81381634Sbrian                                     ntohs(th->th_dport)))
81450867Sbrian      pri++;
81550867Sbrian
81626692Sbrian    if (logit && loglen < sizeof logbuf) {
81781634Sbrian      len = datalen - (th->th_off << 2);
81828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
81981634Sbrian           "TCP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(th->th_sport));
82028679Sbrian      loglen += strlen(logbuf + loglen);
82128679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
82281634Sbrian               "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(th->th_dport));
82328679Sbrian      loglen += strlen(logbuf + loglen);
8246059Samurai      n = 0;
8256059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
82662977Sbrian        if (th->th_flags & mask) {
82762977Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
82862977Sbrian          loglen += strlen(logbuf + loglen);
82962977Sbrian        }
83062977Sbrian        n++;
8316059Samurai      }
83228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
83362977Sbrian               "  seq:%lx  ack:%lx (%d/%d)",
83462977Sbrian               (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
83528679Sbrian      loglen += strlen(logbuf + loglen);
8366059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
83781634Sbrian        const u_short *sp;
8386059Samurai
83981634Sbrian        sp = (const u_short *)(payload + 20);
84062977Sbrian        if (ntohs(sp[0]) == 0x0204) {
84162977Sbrian          snprintf(logbuf + loglen, sizeof logbuf - loglen,
84262977Sbrian                   " MSS = %d", ntohs(sp[1]));
84362977Sbrian          loglen += strlen(logbuf + loglen);
84462977Sbrian        }
8456059Samurai      }
8466059Samurai    }
8476059Samurai    break;
84862778Sbrian
84962778Sbrian  default:
85062778Sbrian    if (prefix)
85162778Sbrian      return -2;
85281634Sbrian
85381634Sbrian    if (logit && loglen < sizeof logbuf) {
85481634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
85581634Sbrian               "<%d>: %s ---> ", cproto, ncpaddr_ntoa(&srcaddr));
85681634Sbrian      loglen += strlen(logbuf + loglen);
85781634Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
85881634Sbrian               "%s (%d)", ncpaddr_ntoa(&dstaddr), nb);
85981634Sbrian      loglen += strlen(logbuf + loglen);
86081634Sbrian    }
86181634Sbrian    break;
8626059Samurai  }
86326692Sbrian
86481634Sbrian  if (filter && FilterCheck(packet, family, filter, psecs)) {
86531142Sbrian    if (logit)
86636285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
86758033Sbrian    result = -1;
8686059Samurai  } else {
86936285Sbrian    /* Check Keep Alive filter */
87058033Sbrian    if (logit && log_IsKept(LogTCPIP)) {
87162977Sbrian      unsigned alivesecs;
87262977Sbrian
87362977Sbrian      alivesecs = 0;
87481634Sbrian      if (filter &&
87581634Sbrian          FilterCheck(packet, family, &bundle->filter.alive, &alivesecs))
87636285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
87762977Sbrian      else if (psecs != NULL) {
87862977Sbrian        if(*psecs == 0)
87962977Sbrian          *psecs = alivesecs;
88062977Sbrian        if (*psecs) {
88162977Sbrian          if (*psecs != alivesecs)
88298243Sbrian            log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n",
88362977Sbrian                       logbuf, *psecs, alivesecs);
88462977Sbrian          else
88562977Sbrian            log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs);
88662977Sbrian        } else
88762977Sbrian          log_Printf(LogTCPIP, "%s\n", logbuf);
88862977Sbrian      }
8896735Samurai    }
89058033Sbrian    result = pri;
8916059Samurai  }
89258033Sbrian
89358776Sbrian  if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
89458033Sbrian    ip_LogDNS(uh, filter->name);
89558033Sbrian
89658033Sbrian  return result;
8976059Samurai}
8986059Samurai
89981634Sbrianstatic int
90081634Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp, u_int32_t af)
90136285Sbrian{
9026059Samurai  int nb, nw;
90331343Sbrian  struct tun_data tun;
90456413Sbrian  char *data;
90562977Sbrian  unsigned secs, alivesecs;
9066059Samurai
90754912Sbrian  nb = m_length(bp);
90847168Sbrian  if (nb > sizeof tun.data) {
90947168Sbrian    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
91047168Sbrian               l->name, nb, (int)(sizeof tun.data));
91154912Sbrian    m_freem(bp);
91281634Sbrian    return 0;
91347168Sbrian  }
91446686Sbrian  mbuf_Read(bp, tun.data, nb);
91526031Sbrian
91662977Sbrian  secs = 0;
91781634Sbrian  if (PacketCheck(bundle, af, tun.data, nb, &bundle->filter.in,
91881634Sbrian                  NULL, &secs) < 0)
91981634Sbrian    return 0;
92026031Sbrian
92162977Sbrian  alivesecs = 0;
92281634Sbrian  if (!FilterCheck(tun.data, af, &bundle->filter.alive, &alivesecs)) {
92362977Sbrian    if (secs == 0)
92462977Sbrian      secs = alivesecs;
92562977Sbrian    bundle_StartIdleTimer(bundle, secs);
92662977Sbrian  }
92726031Sbrian
92856413Sbrian  if (bundle->dev.header) {
92981634Sbrian    tun.header.family = htonl(af);
93056413Sbrian    nb += sizeof tun - sizeof tun.data;
93156413Sbrian    data = (char *)&tun;
93256413Sbrian  } else
93356413Sbrian    data = tun.data;
93456413Sbrian
93556413Sbrian  nw = write(bundle->dev.fd, data, nb);
93646686Sbrian  if (nw != nb) {
93746686Sbrian    if (nw == -1)
93847168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
93947168Sbrian                 l->name, nb, strerror(errno));
94046686Sbrian    else
94147168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
94246686Sbrian  }
94336285Sbrian
94481634Sbrian  return nb;
9456059Samurai}
9466059Samurai
94781634Sbrianstruct mbuf *
94881634Sbrianipv4_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
9496059Samurai{
95081634Sbrian  int nb;
9516059Samurai
95281634Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
95381634Sbrian    log_Printf(LogWARN, "ipv4_Input: IPCP not open - packet dropped\n");
95481634Sbrian    m_freem(bp);
95581634Sbrian    return NULL;
95638557Sbrian  }
9576059Samurai
95881634Sbrian  m_settype(bp, MB_IPIN);
95938544Sbrian
96081634Sbrian  nb = ip_Input(bundle, l, bp, AF_INET);
96181634Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
96238544Sbrian
96381634Sbrian  return NULL;
9647001Samurai}
9657001Samurai
96681634Sbrian#ifndef NOINET6
96781634Sbrianstruct mbuf *
96881634Sbrianipv6_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
9696059Samurai{
97081634Sbrian  int nb;
9716059Samurai
97281897Sbrian  if (bundle->ncp.ipv6cp.fsm.state != ST_OPENED) {
97381634Sbrian    log_Printf(LogWARN, "ipv6_Input: IPV6CP not open - packet dropped\n");
97481634Sbrian    m_freem(bp);
97581634Sbrian    return NULL;
97678411Sbrian  }
97778411Sbrian
97881634Sbrian  m_settype(bp, MB_IPV6IN);
97936285Sbrian
98081634Sbrian  nb = ip_Input(bundle, l, bp, AF_INET6);
98181634Sbrian  ipv6cp_AddInOctets(&bundle->ncp.ipv6cp, nb);
98281634Sbrian
98381634Sbrian  return NULL;
9846059Samurai}
98581634Sbrian#endif
986