ip.c revision 58776
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 58776 2000-03-29 09:31:52Z brian $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai *		o Return ICMP message for filterd packet
246059Samurai *		  and optionaly record it into log.
256059Samurai */
2643313Sbrian#include <sys/param.h>
2731195Sbrian#include <sys/socket.h>
2830715Sbrian#include <netinet/in.h>
296059Samurai#include <netinet/in_systm.h>
306059Samurai#include <netinet/ip.h>
316059Samurai#include <netinet/ip_icmp.h>
326059Samurai#include <netinet/udp.h>
336059Samurai#include <netinet/tcp.h>
3413389Sphk#include <arpa/inet.h>
3536285Sbrian#include <sys/un.h>
3630715Sbrian
3730092Sbrian#include <errno.h>
3830715Sbrian#include <stdio.h>
3930715Sbrian#include <string.h>
4046686Sbrian#include <termios.h>
4130715Sbrian#include <unistd.h>
4230715Sbrian
4346686Sbrian#include "layer.h"
4446686Sbrian#include "proto.h"
4530715Sbrian#include "mbuf.h"
4630715Sbrian#include "log.h"
4730715Sbrian#include "defs.h"
4830715Sbrian#include "timer.h"
4930715Sbrian#include "fsm.h"
5036285Sbrian#include "lqr.h"
5130715Sbrian#include "hdlc.h"
5236285Sbrian#include "throughput.h"
5336285Sbrian#include "iplist.h"
5436285Sbrian#include "slcompress.h"
5536285Sbrian#include "ipcp.h"
566059Samurai#include "filter.h"
5736285Sbrian#include "descriptor.h"
5836285Sbrian#include "lcp.h"
5936285Sbrian#include "ccp.h"
6036285Sbrian#include "link.h"
6136285Sbrian#include "mp.h"
6243313Sbrian#ifndef NORADIUS
6343313Sbrian#include "radius.h"
6443313Sbrian#endif
6536285Sbrian#include "bundle.h"
6631195Sbrian#include "tun.h"
6730715Sbrian#include "ip.h"
686059Samurai
6958033Sbrian
7058033Sbrian#define OPCODE_QUERY	0
7158033Sbrian#define OPCODE_IQUERY	1
7258033Sbrian#define OPCODE_STATUS	2
7358033Sbrian
7458033Sbrianstruct dns_header {
7558033Sbrian  u_short id;
7658033Sbrian  unsigned qr : 1;
7758033Sbrian  unsigned opcode : 4;
7858033Sbrian  unsigned aa : 1;
7958033Sbrian  unsigned tc : 1;
8058033Sbrian  unsigned rd : 1;
8158033Sbrian  unsigned ra : 1;
8258033Sbrian  unsigned z : 3;
8358033Sbrian  unsigned rcode : 4;
8458033Sbrian  u_short qdcount;
8558033Sbrian  u_short ancount;
8658033Sbrian  u_short nscount;
8758033Sbrian  u_short arcount;
8855146Sbrian};
896059Samurai
9058033Sbrianstatic const char *
9158033Sbriandns_Qclass2Txt(u_short qclass)
9258033Sbrian{
9358033Sbrian  static char failure[6];
9458033Sbrian  struct {
9558033Sbrian    u_short id;
9658033Sbrian    const char *txt;
9758033Sbrian  } qtxt[] = {
9858033Sbrian    /* rfc1035 */
9958033Sbrian    { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" }
10058033Sbrian  };
10158033Sbrian  int f;
10258033Sbrian
10358033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
10458033Sbrian    if (qtxt[f].id == qclass)
10558033Sbrian      return qtxt[f].txt;
10658033Sbrian
10758034Sbrian  return HexStr(qclass, failure, sizeof failure);
10858033Sbrian}
10958033Sbrian
11058033Sbrianstatic const char *
11158033Sbriandns_Qtype2Txt(u_short qtype)
11258033Sbrian{
11358033Sbrian  static char failure[6];
11458033Sbrian  struct {
11558033Sbrian    u_short id;
11658033Sbrian    const char *txt;
11758033Sbrian  } qtxt[] = {
11858033Sbrian    /* rfc1035/rfc1700 */
11958033Sbrian    { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" },
12058033Sbrian    { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" },
12158033Sbrian    { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" },
12258033Sbrian    { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" },
12358033Sbrian    { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" },
12458033Sbrian    { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" },
12558033Sbrian    { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" },
12658033Sbrian    { 254, "MAILA" }, { 255, "*" }
12758033Sbrian  };
12858033Sbrian  int f;
12958033Sbrian
13058033Sbrian  for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++)
13158033Sbrian    if (qtxt[f].id == qtype)
13258033Sbrian      return qtxt[f].txt;
13358033Sbrian
13458034Sbrian  return HexStr(qtype, failure, sizeof failure);
13558033Sbrian}
13658033Sbrian
13749140Sbrianstatic __inline int
13828679SbrianPortMatch(int op, u_short pport, u_short rport)
1396059Samurai{
1406059Samurai  switch (op) {
14149140Sbrian  case OP_EQ:
14228679Sbrian    return (pport == rport);
1436059Samurai  case OP_GT:
14428679Sbrian    return (pport > rport);
1456059Samurai  case OP_LT:
14628679Sbrian    return (pport < rport);
1476059Samurai  default:
14828679Sbrian    return (0);
1496059Samurai  }
1506059Samurai}
1516059Samurai
1526059Samurai/*
15346686Sbrian *  Check a packet against a defined filter
15449140Sbrian *  Returns 0 to accept the packet, non-zero to drop the packet
15549140Sbrian *
15649140Sbrian *  If filtering is enabled, the initial fragment of a datagram must
15749140Sbrian *  contain the complete protocol header, and subsequent fragments
15849140Sbrian *  must not attempt to over-write it.
1596059Samurai */
1606059Samuraistatic int
16149140SbrianFilterCheck(const struct ip *pip, const struct filter *filter)
1626059Samurai{
16349140Sbrian  int gotinfo;			/* true if IP payload decoded */
16449140Sbrian  int cproto;			/* P_* protocol type if (gotinfo) */
16549140Sbrian  int estab, syn, finrst;	/* TCP state flags if (gotinfo) */
16649140Sbrian  u_short sport, dport;		/* src, dest port from packet if (gotinfo) */
16749140Sbrian  int n;			/* filter rule to process */
16849140Sbrian  int len;			/* bytes used in dbuff */
16949140Sbrian  int didname;			/* true if filter header printed */
17049140Sbrian  int match;			/* true if condition matched */
17149140Sbrian  const struct filterent *fp = filter->rule;
17236285Sbrian  char dbuff[100];
1736059Samurai
17449140Sbrian  if (fp->f_action == A_NONE)
17549140Sbrian    return (0);		/* No rule is given. Permit this packet */
17636285Sbrian
17749140Sbrian  /* Deny any packet fragment that tries to over-write the header.
17849140Sbrian   * Since we no longer have the real header available, punt on the
17949140Sbrian   * largest normal header - 20 bytes for TCP without options, rounded
18049140Sbrian   * up to the next possible fragment boundary.  Since the smallest
18149140Sbrian   * `legal' MTU is 576, and the smallest recommended MTU is 296, any
18249140Sbrian   * fragmentation within this range is dubious at best */
18349140Sbrian  len = ntohs(pip->ip_off) & IP_OFFMASK;	/* fragment offset */
18449140Sbrian  if (len > 0) {		/* Not first fragment within datagram */
18549140Sbrian    if (len < (24 >> 3))	/* don't allow fragment to over-write header */
18649140Sbrian      return (1);
18749140Sbrian    /* permit fragments on in and out filter */
18851333Sbrian    return (!filter->fragok);
18949140Sbrian  }
19049140Sbrian
19149140Sbrian  cproto = gotinfo = estab = syn = finrst = didname = 0;
19249140Sbrian  sport = dport = 0;
19349140Sbrian  for (n = 0; n < MAXFILTERS; ) {
19449140Sbrian    if (fp->f_action == A_NONE) {
19549140Sbrian      n++;
19649140Sbrian      fp++;
19749140Sbrian      continue;
19849140Sbrian    }
19936285Sbrian
20049140Sbrian    if (!didname) {
20149140Sbrian      log_Printf(LogDEBUG, "%s filter:\n", filter->name);
20249140Sbrian      didname = 1;
20349140Sbrian    }
2046059Samurai
20549140Sbrian    match = 0;
20649140Sbrian    if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) &
20749140Sbrian	  fp->f_src.mask.s_addr) &&
20849140Sbrian	!((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) &
20949140Sbrian	  fp->f_dst.mask.s_addr)) {
21049140Sbrian      if (fp->f_proto != P_NONE) {
21149140Sbrian	if (!gotinfo) {
21249140Sbrian	  const char *ptop = (const char *) pip + (pip->ip_hl << 2);
21349140Sbrian	  const struct tcphdr *th;
21449140Sbrian	  const struct udphdr *uh;
21549140Sbrian	  const struct icmp *ih;
21649140Sbrian	  int datalen;	/* IP datagram length */
21749140Sbrian
21849140Sbrian	  datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
21949140Sbrian	  switch (pip->ip_p) {
22049140Sbrian	  case IPPROTO_ICMP:
22149140Sbrian	    cproto = P_ICMP;
22249140Sbrian	    if (datalen < 8)	/* ICMP must be at least 8 octets */
22349140Sbrian	      return (1);
22449140Sbrian	    ih = (const struct icmp *) ptop;
22549140Sbrian	    sport = ih->icmp_type;
22649140Sbrian	    estab = syn = finrst = -1;
22749140Sbrian	    if (log_IsKept(LogDEBUG))
22849140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
22949140Sbrian	    break;
23049140Sbrian	  case IPPROTO_IGMP:
23149140Sbrian	    cproto = P_IGMP;
23249140Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
23349140Sbrian	      return (1);
23449140Sbrian	    estab = syn = finrst = -1;
23549140Sbrian	    sport = ntohs(0);
23649140Sbrian	    break;
23751809Sbrian#ifdef IPPROTO_GRE
23851809Sbrian          case IPPROTO_GRE:
23951809Sbrian            cproto = P_GRE;
24051809Sbrian            if (datalen < 2)    /* GRE uses 2-octet+ messages */
24151809Sbrian              return (1);
24251809Sbrian            estab = syn = finrst = -1;
24351809Sbrian            sport = ntohs(0);
24451809Sbrian            break;
24551809Sbrian#endif
24649374Sbrian#ifdef IPPROTO_OSPFIGP
24749372Sbrian	  case IPPROTO_OSPFIGP:
24849372Sbrian	    cproto = P_OSPF;
24949372Sbrian	    if (datalen < 8)	/* IGMP uses 8-octet messages */
25049372Sbrian	      return (1);
25149372Sbrian	    estab = syn = finrst = -1;
25249372Sbrian	    sport = ntohs(0);
25349372Sbrian	    break;
25449374Sbrian#endif
25549140Sbrian	  case IPPROTO_UDP:
25649140Sbrian	  case IPPROTO_IPIP:
25749140Sbrian	    cproto = P_UDP;
25849140Sbrian	    if (datalen < 8)	/* UDP header is 8 octets */
25949140Sbrian	      return (1);
26049140Sbrian	    uh = (const struct udphdr *) ptop;
26149140Sbrian	    sport = ntohs(uh->uh_sport);
26249140Sbrian	    dport = ntohs(uh->uh_dport);
26349140Sbrian	    estab = syn = finrst = -1;
26449140Sbrian	    if (log_IsKept(LogDEBUG))
26549140Sbrian	      snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
26649140Sbrian		       sport, dport);
26749140Sbrian	    break;
26849140Sbrian	  case IPPROTO_TCP:
26949140Sbrian	    cproto = P_TCP;
27049140Sbrian	    th = (const struct tcphdr *) ptop;
27149140Sbrian	    /* TCP headers are variable length.  The following code
27249140Sbrian	     * ensures that the TCP header length isn't de-referenced if
27349140Sbrian	     * the datagram is too short
27449140Sbrian	     */
27549140Sbrian	    if (datalen < 20 || datalen < (th->th_off << 2))
27649140Sbrian	      return (1);
27749140Sbrian	    sport = ntohs(th->th_sport);
27849140Sbrian	    dport = ntohs(th->th_dport);
27949140Sbrian	    estab = (th->th_flags & TH_ACK);
28049140Sbrian	    syn = (th->th_flags & TH_SYN);
28149140Sbrian	    finrst = (th->th_flags & (TH_FIN|TH_RST));
28249140Sbrian	    if (log_IsKept(LogDEBUG)) {
28349140Sbrian	      if (!estab)
28449140Sbrian		snprintf(dbuff, sizeof dbuff,
28549140Sbrian			 "flags = %02x, sport = %d, dport = %d",
28649140Sbrian			 th->th_flags, sport, dport);
28749140Sbrian	      else
28849140Sbrian		*dbuff = '\0';
2896059Samurai	    }
29049140Sbrian	    break;
29149140Sbrian	  default:
29249140Sbrian	    return (1);	/* We'll block unknown type of packet */
29349140Sbrian	  }
29426516Sbrian
29549140Sbrian	  if (log_IsKept(LogDEBUG)) {
29649140Sbrian	    if (estab != -1) {
29749140Sbrian	      len = strlen(dbuff);
29849140Sbrian	      snprintf(dbuff + len, sizeof dbuff - len,
29949140Sbrian		       ", estab = %d, syn = %d, finrst = %d",
30049140Sbrian		       estab, syn, finrst);
3016059Samurai	    }
30249140Sbrian	    log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
30349140Sbrian		       filter_Proto2Nam(cproto), dbuff);
3046059Samurai	  }
30549140Sbrian	  gotinfo = 1;
30649140Sbrian	}
30749140Sbrian	if (log_IsKept(LogDEBUG)) {
30849140Sbrian	  if (fp->f_srcop != OP_NONE) {
30949140Sbrian	    snprintf(dbuff, sizeof dbuff, ", src %s %d",
31049140Sbrian		     filter_Op2Nam(fp->f_srcop), fp->f_srcport);
31149140Sbrian	    len = strlen(dbuff);
31249140Sbrian	  } else
31349140Sbrian	    len = 0;
31449140Sbrian	  if (fp->f_dstop != OP_NONE) {
31549140Sbrian	    snprintf(dbuff + len, sizeof dbuff - len,
31649140Sbrian		     ", dst %s %d", filter_Op2Nam(fp->f_dstop),
31749140Sbrian		     fp->f_dstport);
31849140Sbrian	  } else if (!len)
31949140Sbrian	    *dbuff = '\0';
32049140Sbrian
32149140Sbrian	  log_Printf(LogDEBUG, "  rule = %d: Address match, "
32249140Sbrian		     "check against proto %s%s, action = %s\n",
32349140Sbrian		     n, filter_Proto2Nam(fp->f_proto),
32449140Sbrian		     dbuff, filter_Action2Nam(fp->f_action));
32549140Sbrian	}
32649140Sbrian
32749140Sbrian	if (cproto == fp->f_proto) {
32849140Sbrian	  if ((fp->f_srcop == OP_NONE ||
32949140Sbrian	       PortMatch(fp->f_srcop, sport, fp->f_srcport)) &&
33049140Sbrian	      (fp->f_dstop == OP_NONE ||
33149140Sbrian	       PortMatch(fp->f_dstop, dport, fp->f_dstport)) &&
33249140Sbrian	      (fp->f_estab == 0 || estab) &&
33349140Sbrian	      (fp->f_syn == 0 || syn) &&
33449140Sbrian	      (fp->f_finrst == 0 || finrst)) {
33549140Sbrian	    match = 1;
33649140Sbrian	  }
33749140Sbrian	}
33849140Sbrian      } else {
33949140Sbrian	/* Address is matched and no protocol specified. Make a decision. */
34049140Sbrian	log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
34149140Sbrian		   filter_Action2Nam(fp->f_action));
34249140Sbrian	match = 1;
3436059Samurai      }
34449140Sbrian    } else
34549140Sbrian      log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
34649140Sbrian
34749140Sbrian    if (match != fp->f_invert) {
34849140Sbrian      /* Take specified action */
34949140Sbrian      if (fp->f_action < A_NONE)
35049140Sbrian	fp = &filter->rule[n = fp->f_action];
35149140Sbrian      else
35249140Sbrian	return (fp->f_action != A_PERMIT);
35349140Sbrian    } else {
35449140Sbrian      n++;
3556059Samurai      fp++;
3566059Samurai    }
3576059Samurai  }
35849140Sbrian  return (1);		/* No rule is mached. Deny this packet */
3596059Samurai}
3606059Samurai
36136285Sbrian#ifdef notdef
3626059Samuraistatic void
36346828SbrianIcmpError(struct ip *pip, int code)
3646059Samurai{
3656059Samurai  struct mbuf *bp;
3666059Samurai
3676059Samurai  if (pip->ip_p != IPPROTO_ICMP) {
36854912Sbrian    bp = m_get(m_len, MB_IPIN);
36954912Sbrian    memcpy(MBUF_CTOP(bp), ptr, m_len);
37036285Sbrian    vj_SendFrame(bp);
37154912Sbrian    ipcp_AddOutOctets(m_len);
3726059Samurai  }
37336285Sbrian}
3746059Samurai#endif
3756059Samurai
37658033Sbrianstatic void
37758033Sbrianip_LogDNS(const struct udphdr *uh, const char *direction)
37858033Sbrian{
37958033Sbrian  struct dns_header header;
38058033Sbrian  const u_short *pktptr;
38158033Sbrian  const u_char *ptr;
38258033Sbrian  u_short *hptr;
38358033Sbrian  int len;
38458033Sbrian
38558033Sbrian  ptr = (const char *)uh + sizeof *uh;
38658033Sbrian  len = ntohs(uh->uh_ulen) - sizeof *uh;
38758033Sbrian  if (len < sizeof header + 5)		/* rfc1024 */
38858033Sbrian    return;
38958033Sbrian
39058033Sbrian  pktptr = (const u_short *)ptr;
39158033Sbrian  hptr = (u_short *)&header;
39258033Sbrian  ptr += sizeof header;
39358033Sbrian  len -= sizeof header;
39458033Sbrian
39558033Sbrian  while (pktptr < (const u_short *)ptr) {
39658033Sbrian    *hptr++ = ntohs(*pktptr);	/* Careful of macro side-effects ! */
39758033Sbrian    pktptr++;
39858033Sbrian  }
39958033Sbrian
40058033Sbrian  if (header.opcode == OPCODE_QUERY && header.qr == 0) {
40158033Sbrian    /* rfc1035 */
40258033Sbrian    char name[MAXHOSTNAMELEN + 1], *n;
40358033Sbrian    const char *qtype, *qclass;
40458033Sbrian    const u_char *end;
40558033Sbrian
40658033Sbrian    n = name;
40758033Sbrian    end = ptr + len - 4;
40858033Sbrian    if (end - ptr > MAXHOSTNAMELEN)
40958033Sbrian      end = ptr + MAXHOSTNAMELEN;
41058033Sbrian    while (ptr < end) {
41158033Sbrian      len = *ptr++;
41258033Sbrian      if (len > end - ptr)
41358033Sbrian        len = end - ptr;
41458033Sbrian      if (n != name)
41558033Sbrian        *n++ = '.';
41658033Sbrian      memcpy(n, ptr, len);
41758033Sbrian      ptr += len;
41858033Sbrian      n += len;
41958033Sbrian    }
42058033Sbrian    *n = '\0';
42158033Sbrian    qtype = dns_Qtype2Txt(ntohs(*(const u_short *)end));
42258033Sbrian    qclass = dns_Qclass2Txt(ntohs(*(const u_short *)(end + 2)));
42358033Sbrian
42458033Sbrian    log_Printf(LogDNS, "%sbound query %s %s %s\n",
42558033Sbrian               direction, qclass, qtype, name);
42658033Sbrian  }
42758033Sbrian}
42858033Sbrian
4296059Samurai/*
4306059Samurai *  For debugging aid.
4316059Samurai */
4326059Samuraiint
43336285SbrianPacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
4346059Samurai{
43558033Sbrian  static const char *const TcpFlags[] = {
43658033Sbrian    "FIN", "SYN", "RST", "PSH", "ACK", "URG"
43758033Sbrian  };
4386059Samurai  struct ip *pip;
4396059Samurai  struct tcphdr *th;
4406059Samurai  struct udphdr *uh;
4416059Samurai  struct icmp *icmph;
4426059Samurai  char *ptop;
44358033Sbrian  int mask, len, n, pri, logit, loglen, result;
44437010Sbrian  char logbuf[200];
4456059Samurai
44658776Sbrian  logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) &&
44758776Sbrian          (!filter || filter->logok);
44826692Sbrian  loglen = 0;
44958033Sbrian  pri = 0;
4506059Samurai
45158033Sbrian  pip = (struct ip *)cp;
45258033Sbrian  uh = NULL;
4538857Srgrimes
45426692Sbrian  if (logit && loglen < sizeof logbuf) {
45558776Sbrian    if (filter)
45658776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
45758776Sbrian    else
45858776Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen, "  ");
45928679Sbrian    loglen += strlen(logbuf + loglen);
46026692Sbrian  }
4616059Samurai  ptop = (cp + (pip->ip_hl << 2));
4626059Samurai
4636059Samurai  switch (pip->ip_p) {
4646059Samurai  case IPPROTO_ICMP:
46526692Sbrian    if (logit && loglen < sizeof logbuf) {
46628679Sbrian      icmph = (struct icmp *) ptop;
46728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
46828679Sbrian	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
46928679Sbrian      loglen += strlen(logbuf + loglen);
47028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
47128679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
47228679Sbrian      loglen += strlen(logbuf + loglen);
4736059Samurai    }
4746059Samurai    break;
47551048Sbrian
4766059Samurai  case IPPROTO_UDP:
47751048Sbrian    uh = (struct udphdr *) ptop;
47851048Sbrian    if (pip->ip_tos == IPTOS_LOWDELAY)
47951048Sbrian      pri++;
48051048Sbrian
48151048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
48251048Sbrian        ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport),
48351048Sbrian                          ntohs(uh->uh_dport)))
48451048Sbrian      pri++;
48551048Sbrian
48626692Sbrian    if (logit && loglen < sizeof logbuf) {
48728679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
48828679Sbrian	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
48928679Sbrian      loglen += strlen(logbuf + loglen);
49028679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
49128679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
49228679Sbrian      loglen += strlen(logbuf + loglen);
4936059Samurai    }
4946059Samurai    break;
49551048Sbrian
49651809Sbrian#ifdef IPPROTO_GRE
49751809Sbrian  case IPPROTO_GRE:
49851809Sbrian    if (logit && loglen < sizeof logbuf) {
49951809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
50051809Sbrian          "GRE: %s ---> ", inet_ntoa(pip->ip_src));
50151809Sbrian      loglen += strlen(logbuf + loglen);
50251809Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
50351809Sbrian              "%s", inet_ntoa(pip->ip_dst));
50451809Sbrian      loglen += strlen(logbuf + loglen);
50551809Sbrian    }
50651809Sbrian    break;
50751809Sbrian#endif
50851809Sbrian
50949374Sbrian#ifdef IPPROTO_OSPFIGP
51049372Sbrian  case IPPROTO_OSPFIGP:
51149372Sbrian    if (logit && loglen < sizeof logbuf) {
51249372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
51349372Sbrian	   "OSPF: %s ---> ", inet_ntoa(pip->ip_src));
51449372Sbrian      loglen += strlen(logbuf + loglen);
51549372Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
51649372Sbrian	       "%s", inet_ntoa(pip->ip_dst));
51749372Sbrian      loglen += strlen(logbuf + loglen);
51849372Sbrian    }
51949372Sbrian    break;
52049374Sbrian#endif
52151048Sbrian
52236961Sbrian  case IPPROTO_IPIP:
52336961Sbrian    if (logit && loglen < sizeof logbuf) {
52436961Sbrian      uh = (struct udphdr *) ptop;
52536961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
52636961Sbrian	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
52736961Sbrian      loglen += strlen(logbuf + loglen);
52836961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
52936961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
53036961Sbrian      loglen += strlen(logbuf + loglen);
53136961Sbrian    }
53236961Sbrian    break;
53351048Sbrian
53436961Sbrian  case IPPROTO_IGMP:
53536961Sbrian    if (logit && loglen < sizeof logbuf) {
53636961Sbrian      uh = (struct udphdr *) ptop;
53736961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
53836961Sbrian	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
53936961Sbrian      loglen += strlen(logbuf + loglen);
54036961Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
54136961Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
54236961Sbrian      loglen += strlen(logbuf + loglen);
54336961Sbrian    }
54436961Sbrian    break;
54551048Sbrian
5466059Samurai  case IPPROTO_TCP:
54728679Sbrian    th = (struct tcphdr *) ptop;
5486059Samurai    if (pip->ip_tos == IPTOS_LOWDELAY)
54950867Sbrian      pri++;
55051048Sbrian
55151048Sbrian    if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 &&
55251048Sbrian        ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport),
55351048Sbrian                          ntohs(th->th_dport)))
55450867Sbrian      pri++;
55550867Sbrian
55626692Sbrian    if (logit && loglen < sizeof logbuf) {
5576059Samurai      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
55828679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
55928679Sbrian	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
56028679Sbrian      loglen += strlen(logbuf + loglen);
56128679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
56228679Sbrian	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
56328679Sbrian      loglen += strlen(logbuf + loglen);
5646059Samurai      n = 0;
5656059Samurai      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
56626692Sbrian	if (th->th_flags & mask) {
56728679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
56828679Sbrian	  loglen += strlen(logbuf + loglen);
56928679Sbrian	}
5706059Samurai	n++;
5716059Samurai      }
57228679Sbrian      snprintf(logbuf + loglen, sizeof logbuf - loglen,
57337210Sbrian	       "  seq:%lx  ack:%lx (%d/%d)",
57437210Sbrian	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
57528679Sbrian      loglen += strlen(logbuf + loglen);
5766059Samurai      if ((th->th_flags & TH_SYN) && nb > 40) {
57728679Sbrian	u_short *sp;
5786059Samurai
5796059Samurai	ptop += 20;
58028679Sbrian	sp = (u_short *) ptop;
58126692Sbrian	if (ntohs(sp[0]) == 0x0204) {
58228679Sbrian	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
58328679Sbrian		   " MSS = %d", ntohs(sp[1]));
58428679Sbrian	  loglen += strlen(logbuf + loglen);
58528679Sbrian	}
5866059Samurai      }
5876059Samurai    }
5886059Samurai    break;
5896059Samurai  }
59026692Sbrian
59158776Sbrian  if (filter && FilterCheck(pip, filter)) {
59231142Sbrian    if (logit)
59336285Sbrian      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
59436285Sbrian#ifdef notdef
59528679Sbrian    if (direction == 0)
59628679Sbrian      IcmpError(pip, pri);
59736285Sbrian#endif
59858033Sbrian    result = -1;
5996059Samurai  } else {
60036285Sbrian    /* Check Keep Alive filter */
60158033Sbrian    if (logit && log_IsKept(LogTCPIP)) {
60258776Sbrian      if (filter && FilterCheck(pip, &bundle->filter.alive))
60336285Sbrian        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
60436285Sbrian      else
60536285Sbrian        log_Printf(LogTCPIP, "%s\n", logbuf);
6066735Samurai    }
60758033Sbrian    result = pri;
6086059Samurai  }
60958033Sbrian
61058776Sbrian  if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS))
61158033Sbrian    ip_LogDNS(uh, filter->name);
61258033Sbrian
61358033Sbrian  return result;
6146059Samurai}
6156059Samurai
61646686Sbrianstruct mbuf *
61746686Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
61836285Sbrian{
6196059Samurai  int nb, nw;
62031343Sbrian  struct tun_data tun;
62146686Sbrian  struct ip *pip;
62256413Sbrian  char *data;
6236059Samurai
62446686Sbrian  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
62546686Sbrian    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
62654912Sbrian    m_freem(bp);
62746686Sbrian    return NULL;
6286059Samurai  }
6296059Samurai
63054912Sbrian  m_settype(bp, MB_IPIN);
63154912Sbrian  nb = m_length(bp);
63247168Sbrian  if (nb > sizeof tun.data) {
63347168Sbrian    log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n",
63447168Sbrian               l->name, nb, (int)(sizeof tun.data));
63554912Sbrian    m_freem(bp);
63647168Sbrian    return NULL;
63747168Sbrian  }
63846686Sbrian  mbuf_Read(bp, tun.data, nb);
63926031Sbrian
64046686Sbrian  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
64146686Sbrian    return NULL;
64226031Sbrian
64346686Sbrian  pip = (struct ip *)tun.data;
64449140Sbrian  if (!FilterCheck(pip, &bundle->filter.alive))
64546686Sbrian    bundle_StartIdleTimer(bundle);
64626031Sbrian
64746686Sbrian  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
64836285Sbrian
64956413Sbrian  if (bundle->dev.header) {
65056413Sbrian    tun.family = htonl(AF_INET);
65156413Sbrian    nb += sizeof tun - sizeof tun.data;
65256413Sbrian    data = (char *)&tun;
65356413Sbrian  } else
65456413Sbrian    data = tun.data;
65556413Sbrian
65656413Sbrian  nw = write(bundle->dev.fd, data, nb);
65746686Sbrian  if (nw != nb) {
65846686Sbrian    if (nw == -1)
65947168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n",
66047168Sbrian                 l->name, nb, strerror(errno));
66146686Sbrian    else
66247168Sbrian      log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw);
66346686Sbrian  }
66436285Sbrian
66546686Sbrian  return NULL;
6666059Samurai}
6676059Samurai
6686059Samuraivoid
66938557Sbrianip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
6706059Samurai{
6716059Samurai  struct mbuf *bp;
6726059Samurai
67350867Sbrian  if (pri < 0 || pri >= IPCP_QUEUES(ipcp))
67438557Sbrian    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
67538557Sbrian  else {
67646686Sbrian    /*
67746686Sbrian     * We allocate an extra 6 bytes, four at the front and two at the end.
67846686Sbrian     * This is an optimisation so that we need to do less work in
67954912Sbrian     * m_prepend() in acf_LayerPush() and proto_LayerPush() and
68046686Sbrian     * appending in hdlc_LayerPush().
68146686Sbrian     */
68254912Sbrian    bp = m_get(count + 6, MB_IPOUT);
68354912Sbrian    bp->m_offset += 4;
68454912Sbrian    bp->m_len -= 6;
68538557Sbrian    memcpy(MBUF_CTOP(bp), ptr, count);
68654912Sbrian    m_enqueue(ipcp->Queue + pri, bp);
68738557Sbrian  }
6886059Samurai}
6896059Samurai
69038544Sbrianvoid
69138557Sbrianip_DeleteQueue(struct ipcp *ipcp)
69238544Sbrian{
69338544Sbrian  struct mqueue *queue;
69438544Sbrian
69550867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
69638544Sbrian    while (queue->top)
69754912Sbrian      m_freem(m_dequeue(queue));
69838544Sbrian}
69938544Sbrian
70054912Sbriansize_t
70138557Sbrianip_QueueLen(struct ipcp *ipcp)
7027001Samurai{
7037001Samurai  struct mqueue *queue;
70454912Sbrian  size_t result;
70528679Sbrian
70654912Sbrian  result = 0;
70750867Sbrian  for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++)
70854912Sbrian    result += queue->len;
70936285Sbrian
71036285Sbrian  return result;
7117001Samurai}
7127001Samurai
71336285Sbrianint
71446686Sbrianip_PushPacket(struct link *l, struct bundle *bundle)
7156059Samurai{
71638557Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
7176059Samurai  struct mqueue *queue;
7186059Samurai  struct mbuf *bp;
71946686Sbrian  struct ip *pip;
72054912Sbrian  int m_len;
7216059Samurai
72238557Sbrian  if (ipcp->fsm.state != ST_OPENED)
72336285Sbrian    return 0;
72436285Sbrian
72550867Sbrian  queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
72650867Sbrian  do {
7276059Samurai    if (queue->top) {
72854912Sbrian      bp = m_pullup(m_dequeue(queue));
72954912Sbrian      m_len = m_length(bp);
73046686Sbrian      pip = (struct ip *)MBUF_CTOP(bp);
73149140Sbrian      if (!FilterCheck(pip, &bundle->filter.alive))
73246686Sbrian        bundle_StartIdleTimer(bundle);
73350867Sbrian      link_PushPacket(l, bp, bundle, 0, PROTO_IP);
73454912Sbrian      ipcp_AddOutOctets(ipcp, m_len);
73546686Sbrian      return 1;
7366059Samurai    }
73750867Sbrian  } while (queue-- != ipcp->Queue);
73836285Sbrian
73936285Sbrian  return 0;
7406059Samurai}
741