ip.c revision 58033
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 58033 2000-03-14 01:46:49Z 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
10758033Sbrian  snprintf(failure, sizeof failure, "<0x%02x>", qclass);
10858033Sbrian  return failure;
10958033Sbrian}
11058033Sbrian
11158033Sbrianstatic const char *
11258033Sbriandns_Qtype2Txt(u_short qtype)
11358033Sbrian{
11458033Sbrian  static char failure[6];
11558033Sbrian  struct {
11658033Sbrian    u_short id;
11758033Sbrian    const char *txt;
11858033Sbrian  } qtxt[] = {
11958033Sbrian    /* rfc1035/rfc1700 */
12058033Sbrian    { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
12158033Sbrian    { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
12258033Sbrian    { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
12358033Sbrian    { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
12458033Sbrian    { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
12558033Sbrian    { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
12658033Sbrian    { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
12758033Sbrian    { 254, "MAILA" }, { 255, "*" }
12858033Sbrian  };
12958033Sbrian  int f;
13058033Sbrian
13158033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
13258033Sbrian    if (qtxt[f].id == qtype)
13358033Sbrian      return qtxt[f].txt;
13458033Sbrian
13558033Sbrian  snprintf(failure, sizeof failure, "<0x%02x>", qtype);
13658033Sbrian  return failure;
13758033Sbrian}
13858033Sbrian
13949140Sbrianstatic __inline int
14028679SbrianPortMatch(int op, u_short pport, u_short rport)
1416059Samurai{
1426059Samurai  switch (op) {
14349140Sbrian  case OP_EQ:
14428679Sbrian    return (pport == rport);
1456059Samurai  case OP_GT:
14628679Sbrian    return (pport > rport);
1476059Samurai  case OP_LT:
14828679Sbrian    return (pport < rport);
1496059Samurai  default:
15028679Sbrian    return (0);
1516059Samurai  }
1526059Samurai}
1536059Samurai
1546059Samurai/*
15546686Sbrian *  Check a packet against a defined filter
15649140Sbrian *  Returns 0 to accept the packet, non-zero to drop the packet
15749140Sbrian *
15849140Sbrian *  If filtering is enabled, the initial fragment of a datagram must
15949140Sbrian *  contain the complete protocol header, and subsequent fragments
16049140Sbrian *  must not attempt to over-write it.
1616059Samurai */
1626059Samuraistatic int
16349140SbrianFilterCheck(const struct ip *pip, const struct filter *filter)
1646059Samurai{
16549140Sbrian  int gotinfo;			/* true if IP payload decoded */
16649140Sbrian  int cproto;			/* P_* protocol type if (gotinfo) */
16749140Sbrian  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
16849140Sbrian  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
16949140Sbrian  int n;			/* filter rule to process */
17049140Sbrian  int len;			/* bytes used in dbuff */
17149140Sbrian  int didname;			/* true if filter header printed */
17249140Sbrian  int match;			/* true if condition matched */
17349140Sbrian  const struct filterent *fp = filter->rule;
17436285Sbrian  char dbuff[100];
1756059Samurai
17649140Sbrian  if (fp->f_action == A_NONE)
17749140Sbrian    return (0);		/* No rule is given. Permit this packet */
17836285Sbrian
17949140Sbrian  /* Deny any packet fragment that tries to over-write the header.
18049140Sbrian   * Since we no longer have the real header available, punt on the
18149140Sbrian   * largest normal header - 20 bytes for TCP without options, rounded
18249140Sbrian   * up to the next possible fragment boundary.  Since the smallest
18349140Sbrian   * `legal' MTU is 576, and the smallest recommended MTU is 296, any
18449140Sbrian   * fragmentation within this range is dubious at best */
18549140Sbrian  len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
18649140Sbrian  if (len > 0) {		/* Not first fragment within datagram */
18749140Sbrian    if (len < (24 >> 3))	/* don't allow fragment to over-write header */
18849140Sbrian      return (1);
18949140Sbrian    /* permit fragments on in and out filter */
19051333Sbrian    return (!filter->fragok);
19149140Sbrian  }
19249140Sbrian
19349140Sbrian  cproto = gotinfo = estab = syn = finrst = didname = 0;
19449140Sbrian  sport = dport = 0;
19549140Sbrian  for (n = 0; n < MAXFILTERS; ) {
19649140Sbrian    if (fp->f_action == A_NONE) {
19749140Sbrian      n++;
19849140Sbrian      fp++;
19949140Sbrian      continue;
20049140Sbrian    }
20136285Sbrian
20249140Sbrian    if (!didname) {
20349140Sbrian      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
20449140Sbrian      didname = 1;
20549140Sbrian    }
2066059Samurai
20749140Sbrian    match = 0;
20849140Sbrian    if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
20949140Sbrian	  fp->f_src.mask.s_addr) &&
21049140Sbrian	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
21149140Sbrian	  fp->f_dst.mask.s_addr)) {
21249140Sbrian      if (fp->f_proto != P_NONE) {
21349140Sbrian	if (!gotinfo) {
21449140Sbrian	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
21549140Sbrian	  const struct tcphdr *th;
21649140Sbrian	  const struct udphdr *uh;
21749140Sbrian	  const struct icmp *ih;
21849140Sbrian	  int datalen;	/* IP datagram length */
21949140Sbrian
22049140Sbrian	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
22149140Sbrian	  switch (pip->ip_p) {
22249140Sbrian	  case IPPROTO_ICMP:
22349140Sbrian	    cproto = P_ICMP;
22449140Sbrian	    if (datalen < 8)	/* ICMP must be at least 8 octets */
22549140Sbrian	      return (1);
22649140Sbrian	    ih = (const struct icmp *) ptop;
22749140Sbrian	    sport = ih->icmp_type;
22849140Sbrian	    estab = syn = finrst = -1;
22949140Sbrian	    if (log_IsKept(LogDEBUG))
23049140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
23149140Sbrian	    break;
23249140Sbrian	  case IPPROTO_IGMP:
23349140Sbrian	    cproto = P_IGMP;
23449140Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
23549140Sbrian	      return (1);
23649140Sbrian	    estab = syn = finrst = -1;
23749140Sbrian	    sport = ntohs(0);
23849140Sbrian	    break;
23951809Sbrian#ifdef IPPROTO_GRE
24051809Sbrian          case IPPROTO_GRE:
24151809Sbrian            cproto = P_GRE;
24251809Sbrian            if (datalen < 2)    /* GRE uses 2-octet+ messages */
24351809Sbrian              return (1);
24451809Sbrian            estab = syn = finrst = -1;
24551809Sbrian            sport = ntohs(0);
24651809Sbrian            break;
24751809Sbrian#endif
24849374Sbrian#ifdef IPPROTO_OSPFIGP
24949372Sbrian	  case IPPROTO_OSPFIGP:
25049372Sbrian	    cproto = P_OSPF;
25149372Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
25249372Sbrian	      return (1);
25349372Sbrian	    estab = syn = finrst = -1;
25449372Sbrian	    sport = ntohs(0);
25549372Sbrian	    break;
25649374Sbrian#endif
25749140Sbrian	  case IPPROTO_UDP:
25849140Sbrian	  case IPPROTO_IPIP:
25949140Sbrian	    cproto = P_UDP;
26049140Sbrian	    if (datalen < 8)	/* UDP header is 8 octets */
26149140Sbrian	      return (1);
26249140Sbrian	    uh = (const struct udphdr *) ptop;
26349140Sbrian	    sport = ntohs(uh->uh_sport);
26449140Sbrian	    dport = ntohs(uh->uh_dport);
26549140Sbrian	    estab = syn = finrst = -1;
26649140Sbrian	    if (log_IsKept(LogDEBUG))
26749140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
26849140Sbrian		       sport, dport);
26949140Sbrian	    break;
27049140Sbrian	  case IPPROTO_TCP:
27149140Sbrian	    cproto = P_TCP;
27249140Sbrian	    th = (const struct tcphdr *) ptop;
27349140Sbrian	    /* TCP headers are variable length.  The following code
27449140Sbrian	     * ensures that the TCP header length isn't de-referenced if
27549140Sbrian	     * the datagram is too short
27649140Sbrian	     */
27749140Sbrian	    if (datalen < 20 || datalen < (th->th_off << 2))
27849140Sbrian	      return (1);
27949140Sbrian	    sport = ntohs(th->th_sport);
28049140Sbrian	    dport = ntohs(th->th_dport);
28149140Sbrian	    estab = (th->th_flags & TH_ACK);
28249140Sbrian	    syn = (th->th_flags & TH_SYN);
28349140Sbrian	    finrst = (th->th_flags & (TH_FIN|TH_RST));
28449140Sbrian	    if (log_IsKept(LogDEBUG)) {
28549140Sbrian	      if (!estab)
28649140Sbrian		snprintf(dbuff, sizeof dbuff,
28749140Sbrian			 "flags = %02x, sport = %d, dport = %d",
28849140Sbrian			 th->th_flags, sport, dport);
28949140Sbrian	      else
29049140Sbrian		*dbuff = '\0';
2916059Samurai	    }
29249140Sbrian	    break;
29349140Sbrian	  default:
29449140Sbrian	    return (1);	/* We'll block unknown type of packet */
29549140Sbrian	  }
29626516Sbrian
29749140Sbrian	  if (log_IsKept(LogDEBUG)) {
29849140Sbrian	    if (estab != -1) {
29949140Sbrian	      len = strlen(dbuff);
30049140Sbrian	      snprintf(dbuff + len, sizeof dbuff - len,
30149140Sbrian		       ", estab = %d, syn = %d, finrst = %d",
30249140Sbrian		       estab, syn, finrst);
3036059Samurai	    }
30449140Sbrian	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
30549140Sbrian		       filter_Proto2Nam(cproto), dbuff);
3066059Samurai	  }
30749140Sbrian	  gotinfo = 1;
30849140Sbrian	}
30949140Sbrian	if (log_IsKept(LogDEBUG)) {
31049140Sbrian	  if (fp->f_srcop != OP_NONE) {
31149140Sbrian	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
31249140Sbrian		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
31349140Sbrian	    len = strlen(dbuff);
31449140Sbrian	  } else
31549140Sbrian	    len = 0;
31649140Sbrian	  if (fp->f_dstop != OP_NONE) {
31749140Sbrian	    snprintf(dbuff + len, sizeof dbuff - len,
31849140Sbrian		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
31949140Sbrian		     fp->f_dstport);
32049140Sbrian	  } else if (!len)
32149140Sbrian	    *dbuff = '\0';
32249140Sbrian
32349140Sbrian	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
32449140Sbrian		     "check against proto %s%s, action = %s\n",
32549140Sbrian		     n, filter_Proto2Nam(fp->f_proto),
32649140Sbrian		     dbuff, filter_Action2Nam(fp->f_action));
32749140Sbrian	}
32849140Sbrian
32949140Sbrian	if (cproto == fp->f_proto) {
33049140Sbrian	  if ((fp->f_srcop == OP_NONE ||
33149140Sbrian	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
33249140Sbrian	      (fp->f_dstop == OP_NONE ||
33349140Sbrian	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
33449140Sbrian	      (fp->f_estab == 0 || estab) &&
33549140Sbrian	      (fp->f_syn == 0 || syn) &&
33649140Sbrian	      (fp->f_finrst == 0 || finrst)) {
33749140Sbrian	    match = 1;
33849140Sbrian	  }
33949140Sbrian	}
34049140Sbrian      } else {
34149140Sbrian	/* Address is matched and no protocol specified. Make a decision. */
34249140Sbrian	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
34349140Sbrian		   filter_Action2Nam(fp->f_action));
34449140Sbrian	match = 1;
3456059Samurai      }
34649140Sbrian    } else
34749140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
34849140Sbrian
34949140Sbrian    if (match != fp->f_invert) {
35049140Sbrian      /* Take specified action */
35149140Sbrian      if (fp->f_action < A_NONE)
35249140Sbrian	fp = &filter->rule[n = fp->f_action];
35349140Sbrian      else
35449140Sbrian	return (fp->f_action != A_PERMIT);
35549140Sbrian    } else {
35649140Sbrian      n++;
3576059Samurai      fp++;
3586059Samurai    }
3596059Samurai  }
36049140Sbrian  return (1);		/* No rule is mached. Deny this packet */
3616059Samurai}
3626059Samurai
36336285Sbrian#ifdef notdef
3646059Samuraistatic void
36546828SbrianIcmpError(struct ip *pip, int code)
3666059Samurai{
3676059Samurai  struct mbuf *bp;
3686059Samurai
3696059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
37054912Sbrian    bp = m_get(m_len, MB_IPIN);
37154912Sbrian    memcpy(MBUF_CTOP(bp), ptr, m_len);
37236285Sbrian    vj_SendFrame(bp);
37354912Sbrian    ipcp_AddOutOctets(m_len);
3746059Samurai  }
37536285Sbrian}
3766059Samurai#endif
3776059Samurai
37858033Sbrianstatic void
37958033Sbrianip_LogDNS(const struct udphdr *uh, const char *direction)
38058033Sbrian{
38158033Sbrian  struct dns_header header;
38258033Sbrian  const u_short *pktptr;
38358033Sbrian  const u_char *ptr;
38458033Sbrian  u_short *hptr;
38558033Sbrian  int len;
38658033Sbrian
38758033Sbrian  ptr = (const char *)uh + sizeof *uh;
38858033Sbrian  len = ntohs(uh->uh_ulen) - sizeof *uh;
38958033Sbrian  if (len < sizeof header + 5)		/* rfc1024 */
39058033Sbrian    return;
39158033Sbrian
39258033Sbrian  pktptr = (const u_short *)ptr;
39358033Sbrian  hptr = (u_short *)&header;
39458033Sbrian  ptr += sizeof header;
39558033Sbrian  len -= sizeof header;
39658033Sbrian
39758033Sbrian  while (pktptr < (const u_short *)ptr) {
39858033Sbrian    *hptr++ = ntohs(*pktptr);	/* Careful of macro side-effects ! */
39958033Sbrian    pktptr++;
40058033Sbrian  }
40158033Sbrian
40258033Sbrian  if (header.opcode == OPCODE_QUERY && header.qr == 0) {
40358033Sbrian    /* rfc1035 */
40458033Sbrian    char name[MAXHOSTNAMELEN + 1], *n;
40558033Sbrian    const char *qtype, *qclass;
40658033Sbrian    const u_char *end;
40758033Sbrian
40858033Sbrian    n = name;
40958033Sbrian    end = ptr + len - 4;
41058033Sbrian    if (end - ptr > MAXHOSTNAMELEN)
41158033Sbrian      end = ptr + MAXHOSTNAMELEN;
41258033Sbrian    while (ptr < end) {
41358033Sbrian      len = *ptr++;
41458033Sbrian      if (len > end - ptr)
41558033Sbrian        len = end - ptr;
41658033Sbrian      if (n != name)
41758033Sbrian        *n++ = '.';
41858033Sbrian      memcpy(n, ptr, len);
41958033Sbrian      ptr += len;
42058033Sbrian      n += len;
42158033Sbrian    }
42258033Sbrian    *n = '\0';
42358033Sbrian    qtype = dns_Qtype2Txt(ntohs(*(const u_short *)end));
42458033Sbrian    qclass = dns_Qclass2Txt(ntohs(*(const u_short *)(end + 2)));
42558033Sbrian
42658033Sbrian    log_Printf(LogDNS, "%sbound query %s %s %s\n",
42758033Sbrian               direction, qclass, qtype, name);
42858033Sbrian  }
42958033Sbrian}
43058033Sbrian
4316059Samurai/*
4326059Samurai *  For debugging aid.
4336059Samurai */
4346059Samuraiint
43536285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
4366059Samurai{
43758033Sbrian  static const char *const TcpFlags[] = {
43858033Sbrian    "FIN", "SYN", "RST", "PSH", "ACK", "URG"
43958033Sbrian  };
4406059Samurai  struct ip *pip;
4416059Samurai  struct tcphdr *th;
4426059Samurai  struct udphdr *uh;
4436059Samurai  struct icmp *icmph;
4446059Samurai  char *ptop;
44558033Sbrian  int mask, len, n, pri, logit, loglen, result;
44637010Sbrian  char logbuf[200];
4476059Samurai
44858033Sbrian  logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) && filter->logok;
44926692Sbrian  loglen = 0;
45058033Sbrian  pri = 0;
4516059Samurai
45258033Sbrian  pip = (struct ip *)cp;
45358033Sbrian  uh = NULL;
4548857Srgrimes
45526692Sbrian  if (logit && loglen < sizeof logbuf) {
45636285Sbrian    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
45728679Sbrian    loglen += strlen(logbuf + loglen);
45826692Sbrian  }
4596059Samurai  ptop = (cp + (pip->ip_hl << 2));
4606059Samurai
4616059Samurai  switch (pip->ip_p) {
4626059Samurai  case IPPROTO_ICMP:
46326692Sbrian    if (logit && loglen < sizeof logbuf) {
46428679Sbrian      icmph = (struct icmp *) ptop;
46528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
46628679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
46728679Sbrian      loglen += strlen(logbuf + loglen);
46828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
46928679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
47028679Sbrian      loglen += strlen(logbuf + loglen);
4716059Samurai    }
4726059Samurai    break;
47351048Sbrian
4746059Samurai  case IPPROTO_UDP:
47551048Sbrian    uh = (struct udphdr *) ptop;
47651048Sbrian    if (pip->ip_tos == IPTOS_LOWDELAY)
47751048Sbrian      pri++;
47851048Sbrian
47951048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
48051048Sbrian        ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
48151048Sbrian                          ntohs(uh->uh_dport)))
48251048Sbrian      pri++;
48351048Sbrian
48426692Sbrian    if (logit && loglen < sizeof logbuf) {
48528679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
48628679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
48728679Sbrian      loglen += strlen(logbuf + loglen);
48828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
48928679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
49028679Sbrian      loglen += strlen(logbuf + loglen);
4916059Samurai    }
4926059Samurai    break;
49351048Sbrian
49451809Sbrian#ifdef IPPROTO_GRE
49551809Sbrian  case IPPROTO_GRE:
49651809Sbrian    if (logit && loglen < sizeof logbuf) {
49751809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
49851809Sbrian          "GRE: %s ---> ", inet_ntoa(pip->ip_src));
49951809Sbrian      loglen += strlen(logbuf + loglen);
50051809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
50151809Sbrian              "%s", inet_ntoa(pip->ip_dst));
50251809Sbrian      loglen += strlen(logbuf + loglen);
50351809Sbrian    }
50451809Sbrian    break;
50551809Sbrian#endif
50651809Sbrian
50749374Sbrian#ifdef IPPROTO_OSPFIGP
50849372Sbrian  case IPPROTO_OSPFIGP:
50949372Sbrian    if (logit && loglen < sizeof logbuf) {
51049372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
51149372Sbrian	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
51249372Sbrian      loglen += strlen(logbuf + loglen);
51349372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
51449372Sbrian	       "%s", inet_ntoa(pip->ip_dst));
51549372Sbrian      loglen += strlen(logbuf + loglen);
51649372Sbrian    }
51749372Sbrian    break;
51849374Sbrian#endif
51951048Sbrian
52036961Sbrian  case IPPROTO_IPIP:
52136961Sbrian    if (logit && loglen < sizeof logbuf) {
52236961Sbrian      uh = (struct udphdr *) ptop;
52336961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
52436961Sbrian	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
52536961Sbrian      loglen += strlen(logbuf + loglen);
52636961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
52736961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
52836961Sbrian      loglen += strlen(logbuf + loglen);
52936961Sbrian    }
53036961Sbrian    break;
53151048Sbrian
53236961Sbrian  case IPPROTO_IGMP:
53336961Sbrian    if (logit && loglen < sizeof logbuf) {
53436961Sbrian      uh = (struct udphdr *) ptop;
53536961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
53636961Sbrian	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
53736961Sbrian      loglen += strlen(logbuf + loglen);
53836961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
53936961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
54036961Sbrian      loglen += strlen(logbuf + loglen);
54136961Sbrian    }
54236961Sbrian    break;
54351048Sbrian
5446059Samurai  case IPPROTO_TCP:
54528679Sbrian    th = (struct tcphdr *) ptop;
5466059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
54750867Sbrian      pri++;
54851048Sbrian
54951048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
55051048Sbrian        ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
55151048Sbrian                          ntohs(th->th_dport)))
55250867Sbrian      pri++;
55350867Sbrian
55426692Sbrian    if (logit && loglen < sizeof logbuf) {
5556059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
55628679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
55728679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
55828679Sbrian      loglen += strlen(logbuf + loglen);
55928679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
56028679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
56128679Sbrian      loglen += strlen(logbuf + loglen);
5626059Samurai      n = 0;
5636059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
56426692Sbrian	if (th->th_flags & mask) {
56528679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
56628679Sbrian	  loglen += strlen(logbuf + loglen);
56728679Sbrian	}
5686059Samurai	n++;
5696059Samurai      }
57028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
57137210Sbrian	       "  seq:%lx  ack:%lx (%d/%d)",
57237210Sbrian	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
57328679Sbrian      loglen += strlen(logbuf + loglen);
5746059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
57528679Sbrian	u_short *sp;
5766059Samurai
5776059Samurai	ptop += 20;
57828679Sbrian	sp = (u_short *) ptop;
57926692Sbrian	if (ntohs(sp[0]) == 0x0204) {
58028679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
58128679Sbrian		   " MSS = %d", ntohs(sp[1]));
58228679Sbrian	  loglen += strlen(logbuf + loglen);
58328679Sbrian	}
5846059Samurai      }
5856059Samurai    }
5866059Samurai    break;
5876059Samurai  }
58826692Sbrian
58949140Sbrian  if (FilterCheck(pip, filter)) {
59031142Sbrian    if (logit)
59136285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
59236285Sbrian#ifdef notdef
59328679Sbrian    if (direction == 0)
59428679Sbrian      IcmpError(pip, pri);
59536285Sbrian#endif
59658033Sbrian    result = -1;
5976059Samurai  } else {
59836285Sbrian    /* Check Keep Alive filter */
59958033Sbrian    if (logit && log_IsKept(LogTCPIP)) {
60049140Sbrian      if (FilterCheck(pip, &bundle->filter.alive))
60136285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
60236285Sbrian      else
60336285Sbrian        log_Printf(LogTCPIP, "%s\n", logbuf);
6046735Samurai    }
60558033Sbrian    result = pri;
6066059Samurai  }
60758033Sbrian
60858033Sbrian  if (uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
60958033Sbrian    ip_LogDNS(uh, filter->name);
61058033Sbrian
61158033Sbrian  return result;
6126059Samurai}
6136059Samurai
61446686Sbrianstruct mbuf *
61546686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
61636285Sbrian{
6176059Samurai  int nb, nw;
61831343Sbrian  struct tun_data tun;
61946686Sbrian  struct ip *pip;
62056413Sbrian  char *data;
6216059Samurai
62246686Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
62346686Sbrian    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
62454912Sbrian    m_freem(bp);
62546686Sbrian    return NULL;
6266059Samurai  }
6276059Samurai
62854912Sbrian  m_settype(bp, MB_IPIN);
62954912Sbrian  nb = m_length(bp);
63047168Sbrian  if (nb > sizeof tun.data) {
63147168Sbrian    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
63247168Sbrian               l->name, nb, (int)(sizeof tun.data));
63354912Sbrian    m_freem(bp);
63447168Sbrian    return NULL;
63547168Sbrian  }
63646686Sbrian  mbuf_Read(bp, tun.data, nb);
63726031Sbrian
63846686Sbrian  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
63946686Sbrian    return NULL;
64026031Sbrian
64146686Sbrian  pip = (struct ip *)tun.data;
64249140Sbrian  if (!FilterCheck(pip, &bundle->filter.alive))
64346686Sbrian    bundle_StartIdleTimer(bundle);
64426031Sbrian
64546686Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
64636285Sbrian
64756413Sbrian  if (bundle->dev.header) {
64856413Sbrian    tun.family = htonl(AF_INET);
64956413Sbrian    nb += sizeof tun - sizeof tun.data;
65056413Sbrian    data = (char *)&tun;
65156413Sbrian  } else
65256413Sbrian    data = tun.data;
65356413Sbrian
65456413Sbrian  nw = write(bundle->dev.fd, data, nb);
65546686Sbrian  if (nw != nb) {
65646686Sbrian    if (nw == -1)
65747168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
65847168Sbrian                 l->name, nb, strerror(errno));
65946686Sbrian    else
66047168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
66146686Sbrian  }
66236285Sbrian
66346686Sbrian  return NULL;
6646059Samurai}
6656059Samurai
6666059Samuraivoid
66738557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
6686059Samurai{
6696059Samurai  struct mbuf *bp;
6706059Samurai
67150867Sbrian  if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
67238557Sbrian    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
67338557Sbrian  else {
67446686Sbrian    /*
67546686Sbrian     * We allocate an extra 6 bytes, four at the front and two at the end.
67646686Sbrian     * This is an optimisation so that we need to do less work in
67754912Sbrian     * m_prepend() in acf_LayerPush() and proto_LayerPush() and
67846686Sbrian     * appending in hdlc_LayerPush().
67946686Sbrian     */
68054912Sbrian    bp = m_get(count + 6, MB_IPOUT);
68154912Sbrian    bp->m_offset += 4;
68254912Sbrian    bp->m_len -= 6;
68338557Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
68454912Sbrian    m_enqueue(ipcp->Queue + pri, bp);
68538557Sbrian  }
6866059Samurai}
6876059Samurai
68838544Sbrianvoid
68938557Sbrianip_DeleteQueue(struct ipcp *ipcp)
69038544Sbrian{
69138544Sbrian  struct mqueue *queue;
69238544Sbrian
69350867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
69438544Sbrian    while (queue->top)
69554912Sbrian      m_freem(m_dequeue(queue));
69638544Sbrian}
69738544Sbrian
69854912Sbriansize_t
69938557Sbrianip_QueueLen(struct ipcp *ipcp)
7007001Samurai{
7017001Samurai  struct mqueue *queue;
70254912Sbrian  size_t result;
70328679Sbrian
70454912Sbrian  result = 0;
70550867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
70654912Sbrian    result += queue->len;
70736285Sbrian
70836285Sbrian  return result;
7097001Samurai}
7107001Samurai
71136285Sbrianint
71246686Sbrianip_PushPacket(struct link *l, struct bundle *bundle)
7136059Samurai{
71438557Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
7156059Samurai  struct mqueue *queue;
7166059Samurai  struct mbuf *bp;
71746686Sbrian  struct ip *pip;
71854912Sbrian  int m_len;
7196059Samurai
72038557Sbrian  if (ipcp->fsm.state != ST_OPENED)
72136285Sbrian    return 0;
72236285Sbrian
72350867Sbrian  queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
72450867Sbrian  do {
7256059Samurai    if (queue->top) {
72654912Sbrian      bp = m_pullup(m_dequeue(queue));
72754912Sbrian      m_len = m_length(bp);
72846686Sbrian      pip = (struct ip *)MBUF_CTOP(bp);
72949140Sbrian      if (!FilterCheck(pip, &bundle->filter.alive))
73046686Sbrian        bundle_StartIdleTimer(bundle);
73150867Sbrian      link_PushPacket(l, bp, bundle, 0, PROTO_IP);
73254912Sbrian      ipcp_AddOutOctets(ipcp, m_len);
73346686Sbrian      return 1;
7346059Samurai    }
73550867Sbrian  } while (queue-- != ipcp->Queue);
73636285Sbrian
73736285Sbrian  return 0;
7386059Samurai}
739