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