ip.c revision 134833
178189Sbrian/*- 278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org> 378189Sbrian * based on work by Toshiharu OHNO <tony-o@iij.ad.jp> 478189Sbrian * Internet Initiative Japan, Inc (IIJ) 578189Sbrian * All rights reserved. 66059Samurai * 778189Sbrian * Redistribution and use in source and binary forms, with or without 878189Sbrian * modification, are permitted provided that the following conditions 978189Sbrian * are met: 1078189Sbrian * 1. Redistributions of source code must retain the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer. 1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1378189Sbrian * notice, this list of conditions and the following disclaimer in the 1478189Sbrian * documentation and/or other materials provided with the distribution. 156059Samurai * 1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1978189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2678189Sbrian * SUCH DAMAGE. 276059Samurai * 2850479Speter * $FreeBSD: head/usr.sbin/ppp/ip.c 134833 2004-09-06 00:07:58Z marcel $ 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 20981634SbrianFilterCheck(const unsigned char *packet, u_int32_t family, 21081634Sbrian const struct filter *filter, unsigned *psecs) 2116059Samurai{ 21249140Sbrian int gotinfo; /* true if IP payload decoded */ 21381634Sbrian int cproto; /* IPPROTO_* protocol number if (gotinfo) */ 21449140Sbrian int estab, syn, finrst; /* TCP state flags if (gotinfo) */ 21549140Sbrian u_short sport, dport; /* src, dest port from packet if (gotinfo) */ 21649140Sbrian int n; /* filter rule to process */ 21749140Sbrian int len; /* bytes used in dbuff */ 21849140Sbrian int didname; /* true if filter header printed */ 21949140Sbrian int match; /* true if condition matched */ 22081634Sbrian int mindata; /* minimum data size or zero */ 22149140Sbrian const struct filterent *fp = filter->rule; 222129175Sdds char dbuff[100], dstip[16]; 22381634Sbrian struct ncpaddr srcaddr, dstaddr; 22481634Sbrian const char *payload; /* IP payload */ 22581634Sbrian int datalen; /* IP datagram length */ 2266059Samurai 22749140Sbrian if (fp->f_action == A_NONE) 22862977Sbrian return 0; /* No rule is given. Permit this packet */ 22936285Sbrian 23081634Sbrian#ifndef NOINET6 23181634Sbrian if (family == AF_INET6) { 23281634Sbrian const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet; 23381634Sbrian 23481634Sbrian ncpaddr_setip6(&srcaddr, &pip6->ip6_src); 23581634Sbrian ncpaddr_setip6(&dstaddr, &pip6->ip6_dst); 23681738Sbrian datalen = ntohs(pip6->ip6_plen); 23781738Sbrian payload = packet + sizeof *pip6; 23881634Sbrian cproto = pip6->ip6_nxt; 23981634Sbrian } else 24081634Sbrian#endif 24181634Sbrian { 24281634Sbrian /* 24381634Sbrian * Deny any packet fragment that tries to over-write the header. 24481634Sbrian * Since we no longer have the real header available, punt on the 24581634Sbrian * largest normal header - 20 bytes for TCP without options, rounded 24681634Sbrian * up to the next possible fragment boundary. Since the smallest 24781634Sbrian * `legal' MTU is 576, and the smallest recommended MTU is 296, any 24881634Sbrian * fragmentation within this range is dubious at best 24981634Sbrian */ 25081634Sbrian const struct ip *pip = (const struct ip *)packet; 25181634Sbrian 25298243Sbrian len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */ 25381634Sbrian if (len > 0) { /* Not first fragment within datagram */ 25481634Sbrian if (len < (24 >> 3)) { /* don't allow fragment to over-write header */ 25581634Sbrian log_Printf(LogFILTER, " error: illegal header\n"); 25681634Sbrian return 1; 25781634Sbrian } 25881634Sbrian /* permit fragments on in and out filter */ 25981634Sbrian if (!filter->fragok) { 26081634Sbrian log_Printf(LogFILTER, " error: illegal fragmentation\n"); 26181634Sbrian return 1; 26281634Sbrian } else 26381634Sbrian return 0; 26465181Sbrian } 26598243Sbrian 26681634Sbrian ncpaddr_setip4(&srcaddr, pip->ip_src); 26781634Sbrian ncpaddr_setip4(&dstaddr, pip->ip_dst); 26881634Sbrian datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 26981634Sbrian payload = packet + (pip->ip_hl << 2); 27081634Sbrian cproto = pip->ip_p; 27149140Sbrian } 27281634Sbrian 273129175Sdds 27481634Sbrian gotinfo = estab = syn = finrst = didname = 0; 27549140Sbrian sport = dport = 0; 27681634Sbrian 27749140Sbrian for (n = 0; n < MAXFILTERS; ) { 27849140Sbrian if (fp->f_action == A_NONE) { 27949140Sbrian n++; 28049140Sbrian fp++; 28149140Sbrian continue; 28249140Sbrian } 28336285Sbrian 28449140Sbrian if (!didname) { 28549140Sbrian log_Printf(LogDEBUG, "%s filter:\n", filter->name); 28649140Sbrian didname = 1; 28749140Sbrian } 2886059Samurai 28949140Sbrian match = 0; 29081634Sbrian 29181634Sbrian if ((ncprange_family(&fp->f_src) == AF_UNSPEC || 29281634Sbrian ncprange_contains(&fp->f_src, &srcaddr)) && 29381634Sbrian (ncprange_family(&fp->f_dst) == AF_UNSPEC || 29481634Sbrian ncprange_contains(&fp->f_dst, &dstaddr))) { 29581634Sbrian if (fp->f_proto != 0) { 29662977Sbrian if (!gotinfo) { 29762977Sbrian const struct tcphdr *th; 29862977Sbrian const struct udphdr *uh; 29962977Sbrian const struct icmp *ih; 30081634Sbrian#ifndef NOINET6 30181634Sbrian const struct icmp6_hdr *ih6; 30281634Sbrian#endif 30381634Sbrian mindata = 0; 30481634Sbrian sport = dport = 0; 30581634Sbrian estab = syn = finrst = -1; 30649140Sbrian 30781634Sbrian switch (cproto) { 30862977Sbrian case IPPROTO_ICMP: 30981634Sbrian mindata = 8; /* ICMP must be at least 8 octets */ 31081634Sbrian ih = (const struct icmp *)payload; 311112660Sbrian sport = ih->icmp_type; 31281634Sbrian if (log_IsKept(LogDEBUG)) 31381634Sbrian snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 31481634Sbrian break; 31565181Sbrian 31681634Sbrian#ifndef NOINET6 31781634Sbrian case IPPROTO_ICMPV6: 31881634Sbrian mindata = 8; /* ICMP must be at least 8 octets */ 31981634Sbrian ih6 = (const struct icmp6_hdr *)payload; 320112660Sbrian sport = ih6->icmp6_type; 32162977Sbrian if (log_IsKept(LogDEBUG)) 32262977Sbrian snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 32362977Sbrian break; 32481634Sbrian#endif 32581634Sbrian 32662977Sbrian case IPPROTO_IGMP: 32781634Sbrian mindata = 8; /* IGMP uses 8-octet messages */ 32862977Sbrian break; 32981634Sbrian 33051809Sbrian#ifdef IPPROTO_GRE 33151809Sbrian case IPPROTO_GRE: 33281634Sbrian mindata = 2; /* GRE uses 2-octet+ messages */ 33351809Sbrian break; 33451809Sbrian#endif 33549374Sbrian#ifdef IPPROTO_OSPFIGP 33662977Sbrian case IPPROTO_OSPFIGP: 33781634Sbrian mindata = 8; /* IGMP uses 8-octet messages */ 33862977Sbrian break; 33949374Sbrian#endif 34081634Sbrian#ifndef NOINET6 34181634Sbrian case IPPROTO_IPV6: 34281634Sbrian mindata = 20; /* RFC2893 Section 3.5: 5 * 32bit words */ 34365846Sbrian break; 34481634Sbrian#endif 34581634Sbrian 34662977Sbrian case IPPROTO_UDP: 34781634Sbrian mindata = 8; /* UDP header is 8 octets */ 34881634Sbrian uh = (const struct udphdr *)payload; 34962977Sbrian sport = ntohs(uh->uh_sport); 35062977Sbrian dport = ntohs(uh->uh_dport); 35162977Sbrian if (log_IsKept(LogDEBUG)) 35262977Sbrian snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 35362977Sbrian sport, dport); 35462977Sbrian break; 35581634Sbrian 35662977Sbrian case IPPROTO_TCP: 35781634Sbrian th = (const struct tcphdr *)payload; 35881634Sbrian /* 35981634Sbrian * TCP headers are variable length. The following code 36062977Sbrian * ensures that the TCP header length isn't de-referenced if 36162977Sbrian * the datagram is too short 36262977Sbrian */ 36365181Sbrian if (datalen < 20 || datalen < (th->th_off << 2)) { 36465181Sbrian log_Printf(LogFILTER, " error: TCP header incorrect\n"); 36562977Sbrian return 1; 36665181Sbrian } 36762977Sbrian sport = ntohs(th->th_sport); 36862977Sbrian dport = ntohs(th->th_dport); 36962977Sbrian estab = (th->th_flags & TH_ACK); 37062977Sbrian syn = (th->th_flags & TH_SYN); 37162977Sbrian finrst = (th->th_flags & (TH_FIN|TH_RST)); 37262977Sbrian if (log_IsKept(LogDEBUG)) { 37362977Sbrian if (!estab) 37462977Sbrian snprintf(dbuff, sizeof dbuff, 37562977Sbrian "flags = %02x, sport = %d, dport = %d", 37662977Sbrian th->th_flags, sport, dport); 37762977Sbrian else 37862977Sbrian *dbuff = '\0'; 37962977Sbrian } 38062977Sbrian break; 38162977Sbrian default: 38281634Sbrian break; 38362977Sbrian } 38426516Sbrian 38581634Sbrian if (datalen < mindata) { 38681634Sbrian log_Printf(LogFILTER, " error: proto %s must be at least" 387129175Sdds " %d octets\n", prototxt(cproto), mindata); 38881634Sbrian return 1; 38981634Sbrian } 39081634Sbrian 39162977Sbrian if (log_IsKept(LogDEBUG)) { 39262977Sbrian if (estab != -1) { 39362977Sbrian len = strlen(dbuff); 39462977Sbrian snprintf(dbuff + len, sizeof dbuff - len, 39562977Sbrian ", estab = %d, syn = %d, finrst = %d", 39662977Sbrian estab, syn, finrst); 39762977Sbrian } 398129175Sdds log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 399129175Sdds prototxt(cproto), dbuff); 40062977Sbrian } 40162977Sbrian gotinfo = 1; 40262977Sbrian } 40381634Sbrian 40462977Sbrian if (log_IsKept(LogDEBUG)) { 40562977Sbrian if (fp->f_srcop != OP_NONE) { 40662977Sbrian snprintf(dbuff, sizeof dbuff, ", src %s %d", 40762977Sbrian filter_Op2Nam(fp->f_srcop), fp->f_srcport); 40862977Sbrian len = strlen(dbuff); 40962977Sbrian } else 41062977Sbrian len = 0; 41162977Sbrian if (fp->f_dstop != OP_NONE) { 41262977Sbrian snprintf(dbuff + len, sizeof dbuff - len, 41362977Sbrian ", dst %s %d", filter_Op2Nam(fp->f_dstop), 41462977Sbrian fp->f_dstport); 41562977Sbrian } else if (!len) 41662977Sbrian *dbuff = '\0'; 41749140Sbrian 41862977Sbrian log_Printf(LogDEBUG, " rule = %d: Address match, " 41981634Sbrian "check against proto %d%s, action = %s\n", 42081634Sbrian n, fp->f_proto, dbuff, filter_Action2Nam(fp->f_action)); 42162977Sbrian } 42249140Sbrian 42362977Sbrian if (cproto == fp->f_proto) { 42462977Sbrian if ((fp->f_srcop == OP_NONE || 42562977Sbrian PortMatch(fp->f_srcop, sport, fp->f_srcport)) && 42662977Sbrian (fp->f_dstop == OP_NONE || 42762977Sbrian PortMatch(fp->f_dstop, dport, fp->f_dstport)) && 42862977Sbrian (fp->f_estab == 0 || estab) && 42962977Sbrian (fp->f_syn == 0 || syn) && 43062977Sbrian (fp->f_finrst == 0 || finrst)) { 43162977Sbrian match = 1; 43262977Sbrian } 43362977Sbrian } 43449140Sbrian } else { 43562977Sbrian /* Address is matched and no protocol specified. Make a decision. */ 43662977Sbrian log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 43762977Sbrian filter_Action2Nam(fp->f_action)); 43862977Sbrian match = 1; 4396059Samurai } 44049140Sbrian } else 44149140Sbrian log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 44249140Sbrian 44349140Sbrian if (match != fp->f_invert) { 44449140Sbrian /* Take specified action */ 44549140Sbrian if (fp->f_action < A_NONE) 44662977Sbrian fp = &filter->rule[n = fp->f_action]; 44765181Sbrian else { 44862977Sbrian if (fp->f_action == A_PERMIT) { 44962977Sbrian if (psecs != NULL) 45062977Sbrian *psecs = fp->timeout; 45165181Sbrian if (strcmp(filter->name, "DIAL") == 0) { 45265181Sbrian /* If dial filter then even print out accept packets */ 45365181Sbrian if (log_IsKept(LogFILTER)) { 45481634Sbrian snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr)); 45565181Sbrian log_Printf(LogFILTER, "%sbound rule = %d accept %s " 456129175Sdds "src = %s:%d dst = %s:%d\n", filter->name, n, 457129175Sdds prototxt(cproto), ncpaddr_ntoa(&srcaddr), sport, 458129175Sdds dstip, dport); 45965181Sbrian } 46065181Sbrian } 46162977Sbrian return 0; 46265181Sbrian } else { 46365181Sbrian if (log_IsKept(LogFILTER)) { 46481634Sbrian snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr)); 46598243Sbrian log_Printf(LogFILTER, 46698243Sbrian "%sbound rule = %d deny %s src = %s/%d dst = %s/%d\n", 467129175Sdds filter->name, n, prototxt(cproto), 46881634Sbrian ncpaddr_ntoa(&srcaddr), sport, dstip, dport); 46965181Sbrian } 47098243Sbrian return 1; 47181634Sbrian } /* Explict match. Deny this packet */ 47265181Sbrian } 47349140Sbrian } else { 47449140Sbrian n++; 4756059Samurai fp++; 4766059Samurai } 4776059Samurai } 47865181Sbrian 47965181Sbrian if (log_IsKept(LogFILTER)) { 48081634Sbrian snprintf(dstip, sizeof dstip, "%s", ncpaddr_ntoa(&dstaddr)); 48198243Sbrian log_Printf(LogFILTER, 48298243Sbrian "%sbound rule = implicit deny %s src = %s/%d dst = %s/%d\n", 483129175Sdds filter->name, prototxt(cproto), ncpaddr_ntoa(&srcaddr), 484129175Sdds sport, dstip, dport); 48565181Sbrian } 48665181Sbrian 48781634Sbrian return 1; /* No rule matched, deny this packet */ 4886059Samurai} 4896059Samurai 4906059Samuraistatic void 49158033Sbrianip_LogDNS(const struct udphdr *uh, const char *direction) 49258033Sbrian{ 49358033Sbrian struct dns_header header; 49458033Sbrian const u_short *pktptr; 49558033Sbrian const u_char *ptr; 49677487Sbrian u_short *hptr, tmp; 497134789Sbrian unsigned len; 49858033Sbrian 49958033Sbrian ptr = (const char *)uh + sizeof *uh; 50058033Sbrian len = ntohs(uh->uh_ulen) - sizeof *uh; 50158033Sbrian if (len < sizeof header + 5) /* rfc1024 */ 50258033Sbrian return; 50358033Sbrian 50458033Sbrian pktptr = (const u_short *)ptr; 50558033Sbrian hptr = (u_short *)&header; 50658033Sbrian ptr += sizeof header; 50758033Sbrian len -= sizeof header; 50858033Sbrian 50958033Sbrian while (pktptr < (const u_short *)ptr) { 51062977Sbrian *hptr++ = ntohs(*pktptr); /* Careful of macro side-effects ! */ 51158033Sbrian pktptr++; 51258033Sbrian } 51358033Sbrian 51458033Sbrian if (header.opcode == OPCODE_QUERY && header.qr == 0) { 51558033Sbrian /* rfc1035 */ 51674049Sbrian char namewithdot[MAXHOSTNAMELEN + 1], *n; 51758033Sbrian const char *qtype, *qclass; 51858033Sbrian const u_char *end; 51958033Sbrian 52074049Sbrian n = namewithdot; 52158033Sbrian end = ptr + len - 4; 522134789Sbrian if (end - ptr >= (int)sizeof namewithdot) 52374049Sbrian end = ptr + sizeof namewithdot - 1; 52458033Sbrian while (ptr < end) { 52558033Sbrian len = *ptr++; 526134789Sbrian if ((int)len > end - ptr) 52758033Sbrian len = end - ptr; 52874049Sbrian if (n != namewithdot) 52958033Sbrian *n++ = '.'; 53058033Sbrian memcpy(n, ptr, len); 53158033Sbrian ptr += len; 53258033Sbrian n += len; 53358033Sbrian } 53458033Sbrian *n = '\0'; 53558033Sbrian 53677487Sbrian if (log_IsKept(LogDNS)) { 53777487Sbrian memcpy(&tmp, end, sizeof tmp); 53877487Sbrian qtype = dns_Qtype2Txt(ntohs(tmp)); 53977487Sbrian memcpy(&tmp, end + 2, sizeof tmp); 54077487Sbrian qclass = dns_Qclass2Txt(ntohs(tmp)); 54177487Sbrian 54277487Sbrian log_Printf(LogDNS, "%sbound query %s %s %s\n", 54377487Sbrian direction, qclass, qtype, namewithdot); 54477487Sbrian } 54558033Sbrian } 54658033Sbrian} 54758033Sbrian 5486059Samurai/* 54981634Sbrian * Check if the given packet matches the given filter. 55081634Sbrian * One of pip or pip6 must be set. 5516059Samurai */ 5526059Samuraiint 55381634SbrianPacketCheck(struct bundle *bundle, u_int32_t family, 55481634Sbrian const unsigned char *packet, int nb, struct filter *filter, 55581634Sbrian const char *prefix, unsigned *psecs) 5566059Samurai{ 557134789Sbrian char logbuf[200]; 55858033Sbrian static const char *const TcpFlags[] = { 55958033Sbrian "FIN", "SYN", "RST", "PSH", "ACK", "URG" 56058033Sbrian }; 56181634Sbrian const struct tcphdr *th; 56281634Sbrian const struct udphdr *uh; 56381634Sbrian const struct icmp *icmph; 56481634Sbrian#ifndef NOINET6 56581634Sbrian const struct icmp6_hdr *icmp6h; 56681634Sbrian#endif 56781634Sbrian const unsigned char *payload; 56881634Sbrian struct ncpaddr srcaddr, dstaddr; 569134789Sbrian int cproto, mask, len, n, pri, logit, result, datalen, frag; 570134789Sbrian unsigned loglen; 57181634Sbrian u_char tos; 5726059Samurai 57358776Sbrian logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) && 57458776Sbrian (!filter || filter->logok); 57526692Sbrian loglen = 0; 57658033Sbrian pri = 0; 5776059Samurai 57881634Sbrian#ifndef NOINET6 57981634Sbrian if (family == AF_INET6) { 58081634Sbrian const struct ip6_hdr *pip6 = (const struct ip6_hdr *)packet; 58181634Sbrian 58281634Sbrian ncpaddr_setip6(&srcaddr, &pip6->ip6_src); 58381634Sbrian ncpaddr_setip6(&dstaddr, &pip6->ip6_dst); 58481634Sbrian datalen = ntohs(pip6->ip6_plen); 58581634Sbrian payload = packet + sizeof *pip6; 58681634Sbrian cproto = pip6->ip6_nxt; 58781738Sbrian tos = 0; /* XXX: pip6->ip6_vfc >> 4 ? */ 58881634Sbrian frag = 0; /* XXX: ??? */ 58981634Sbrian } else 59081634Sbrian#endif 59181634Sbrian { 59281634Sbrian const struct ip *pip = (const struct ip *)packet; 59381634Sbrian 59481634Sbrian ncpaddr_setip4(&srcaddr, pip->ip_src); 59581634Sbrian ncpaddr_setip4(&dstaddr, pip->ip_dst); 59681634Sbrian datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 59781634Sbrian payload = packet + (pip->ip_hl << 2); 59881634Sbrian cproto = pip->ip_p; 59981634Sbrian tos = pip->ip_tos; 60081634Sbrian frag = ntohs(pip->ip_off) & IP_OFFMASK; 60181634Sbrian } 60281634Sbrian 60358033Sbrian uh = NULL; 6048857Srgrimes 60526692Sbrian if (logit && loglen < sizeof logbuf) { 60662778Sbrian if (prefix) 60762778Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s", prefix); 60862778Sbrian else if (filter) 60958776Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 61058776Sbrian else 61158776Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " "); 61228679Sbrian loglen += strlen(logbuf + loglen); 61326692Sbrian } 6146059Samurai 61581634Sbrian switch (cproto) { 6166059Samurai case IPPROTO_ICMP: 61726692Sbrian if (logit && loglen < sizeof logbuf) { 61881634Sbrian len = datalen - sizeof *icmph; 61981634Sbrian icmph = (const struct icmp *)payload; 62028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 62181634Sbrian "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmph->icmp_type); 62228679Sbrian loglen += strlen(logbuf + loglen); 62328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 62481634Sbrian "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb); 62528679Sbrian loglen += strlen(logbuf + loglen); 6266059Samurai } 6276059Samurai break; 62851048Sbrian 62981634Sbrian#ifndef NOINET6 63081634Sbrian case IPPROTO_ICMPV6: 63181634Sbrian if (logit && loglen < sizeof logbuf) { 63281634Sbrian len = datalen - sizeof *icmp6h; 63381634Sbrian icmp6h = (const struct icmp6_hdr *)payload; 63481634Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 63581634Sbrian "ICMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), icmp6h->icmp6_type); 63681634Sbrian loglen += strlen(logbuf + loglen); 63781634Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 63881634Sbrian "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), len, nb); 63981634Sbrian loglen += strlen(logbuf + loglen); 64081634Sbrian } 64181634Sbrian break; 64281634Sbrian#endif 64381634Sbrian 6446059Samurai case IPPROTO_UDP: 64581634Sbrian uh = (const struct udphdr *)payload; 64681634Sbrian if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos) 64751048Sbrian pri++; 64851048Sbrian 64981634Sbrian if (!frag && ncp_IsUrgentUdpPort(&bundle->ncp, ntohs(uh->uh_sport), 65081634Sbrian ntohs(uh->uh_dport))) 65151048Sbrian pri++; 65251048Sbrian 65326692Sbrian if (logit && loglen < sizeof logbuf) { 65481634Sbrian len = datalen - sizeof *uh; 65528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 65681634Sbrian "UDP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(uh->uh_sport)); 65728679Sbrian loglen += strlen(logbuf + loglen); 65828679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 65981634Sbrian "%s:%d (%d/%d)", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport), 66062977Sbrian len, nb); 66128679Sbrian loglen += strlen(logbuf + loglen); 6626059Samurai } 66362778Sbrian 66462778Sbrian if (Enabled(bundle, OPT_FILTERDECAP) && 66581634Sbrian payload[sizeof *uh] == HDLC_ADDR && 66681634Sbrian payload[sizeof *uh + 1] == HDLC_UI) { 66762778Sbrian u_short proto; 66862778Sbrian const char *type; 66962778Sbrian 67081634Sbrian memcpy(&proto, payload + sizeof *uh + 2, sizeof proto); 67162778Sbrian type = NULL; 67262778Sbrian 67362778Sbrian switch (ntohs(proto)) { 67462778Sbrian case PROTO_IP: 67562778Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains "); 67681634Sbrian result = PacketCheck(bundle, AF_INET, payload + sizeof *uh + 4, 67781634Sbrian nb - (payload - packet) - sizeof *uh - 4, filter, 67862977Sbrian logbuf, psecs); 67962778Sbrian if (result != -2) 68062778Sbrian return result; 68162778Sbrian type = "IP"; 68262778Sbrian break; 68362778Sbrian 68462778Sbrian case PROTO_VJUNCOMP: type = "compressed VJ"; break; 68562778Sbrian case PROTO_VJCOMP: type = "uncompressed VJ"; break; 68662778Sbrian case PROTO_MP: type = "Multi-link"; break; 68762778Sbrian case PROTO_ICOMPD: type = "Individual link CCP"; break; 68862778Sbrian case PROTO_COMPD: type = "CCP"; break; 68962778Sbrian case PROTO_IPCP: type = "IPCP"; break; 69062778Sbrian case PROTO_LCP: type = "LCP"; break; 69162778Sbrian case PROTO_PAP: type = "PAP"; break; 69262778Sbrian case PROTO_CBCP: type = "CBCP"; break; 69362778Sbrian case PROTO_LQR: type = "LQR"; break; 69462778Sbrian case PROTO_CHAP: type = "CHAP"; break; 69562778Sbrian } 69662778Sbrian if (type) { 69762778Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 69862778Sbrian " - %s data", type); 69962778Sbrian loglen += strlen(logbuf + loglen); 70062778Sbrian } 70162778Sbrian } 70262778Sbrian 7036059Samurai break; 70451048Sbrian 70551809Sbrian#ifdef IPPROTO_GRE 70651809Sbrian case IPPROTO_GRE: 70751809Sbrian if (logit && loglen < sizeof logbuf) { 70851809Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 70981634Sbrian "GRE: %s ---> ", ncpaddr_ntoa(&srcaddr)); 71051809Sbrian loglen += strlen(logbuf + loglen); 71151809Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 71281634Sbrian "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb); 71351809Sbrian loglen += strlen(logbuf + loglen); 71451809Sbrian } 71551809Sbrian break; 71651809Sbrian#endif 71751809Sbrian 71849374Sbrian#ifdef IPPROTO_OSPFIGP 71949372Sbrian case IPPROTO_OSPFIGP: 72049372Sbrian if (logit && loglen < sizeof logbuf) { 72149372Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 72281634Sbrian "OSPF: %s ---> ", ncpaddr_ntoa(&srcaddr)); 72349372Sbrian loglen += strlen(logbuf + loglen); 72449372Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 72581634Sbrian "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb); 72649372Sbrian loglen += strlen(logbuf + loglen); 72749372Sbrian } 72849372Sbrian break; 72949374Sbrian#endif 73051048Sbrian 73181634Sbrian#ifndef NOINET6 73281634Sbrian case IPPROTO_IPV6: 73381634Sbrian if (logit && loglen < sizeof logbuf) { 73481634Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 73581634Sbrian "IPv6: %s ---> ", ncpaddr_ntoa(&srcaddr)); 73681634Sbrian loglen += strlen(logbuf + loglen); 73781634Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 73881634Sbrian "%s (%d/%d)", ncpaddr_ntoa(&dstaddr), datalen, nb); 73981634Sbrian loglen += strlen(logbuf + loglen); 74081634Sbrian } 74181634Sbrian 74281634Sbrian if (Enabled(bundle, OPT_FILTERDECAP)) { 74381634Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains "); 74481634Sbrian result = PacketCheck(bundle, AF_INET6, payload, nb - (payload - packet), 74581634Sbrian filter, logbuf, psecs); 74681634Sbrian if (result != -2) 74781634Sbrian return result; 74881634Sbrian } 74981634Sbrian break; 75081634Sbrian#endif 75181634Sbrian 75236961Sbrian case IPPROTO_IPIP: 75336961Sbrian if (logit && loglen < sizeof logbuf) { 75436961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 75581634Sbrian "IPIP: %s ---> ", ncpaddr_ntoa(&srcaddr)); 75636961Sbrian loglen += strlen(logbuf + loglen); 75736961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 75881634Sbrian "%s", ncpaddr_ntoa(&dstaddr)); 75936961Sbrian loglen += strlen(logbuf + loglen); 76081634Sbrian } 76175894Sbrian 76281634Sbrian if (Enabled(bundle, OPT_FILTERDECAP) && 76381634Sbrian ((const struct ip *)payload)->ip_v == 4) { 76481634Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " contains "); 76581634Sbrian result = PacketCheck(bundle, AF_INET, payload, nb - (payload - packet), 76681634Sbrian filter, logbuf, psecs); 767134789Sbrian loglen += strlen(logbuf + loglen); 76881634Sbrian if (result != -2) 76981634Sbrian return result; 77036961Sbrian } 77136961Sbrian break; 77251048Sbrian 77365846Sbrian case IPPROTO_ESP: 77465846Sbrian if (logit && loglen < sizeof logbuf) { 77565846Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 77681634Sbrian "ESP: %s ---> ", ncpaddr_ntoa(&srcaddr)); 77765846Sbrian loglen += strlen(logbuf + loglen); 77871781Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p", 77981634Sbrian ncpaddr_ntoa(&dstaddr), payload); 78065846Sbrian loglen += strlen(logbuf + loglen); 78165846Sbrian } 78265846Sbrian break; 78365846Sbrian 78465846Sbrian case IPPROTO_AH: 78565846Sbrian if (logit && loglen < sizeof logbuf) { 78665846Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 78781634Sbrian "AH: %s ---> ", ncpaddr_ntoa(&srcaddr)); 78865846Sbrian loglen += strlen(logbuf + loglen); 78971781Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s, spi %p", 79081634Sbrian ncpaddr_ntoa(&dstaddr), payload + sizeof(u_int32_t)); 79165846Sbrian loglen += strlen(logbuf + loglen); 79265846Sbrian } 79365846Sbrian break; 79465846Sbrian 79536961Sbrian case IPPROTO_IGMP: 79636961Sbrian if (logit && loglen < sizeof logbuf) { 79781634Sbrian uh = (const struct udphdr *)payload; 79836961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 79981634Sbrian "IGMP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), 80062977Sbrian ntohs(uh->uh_sport)); 80136961Sbrian loglen += strlen(logbuf + loglen); 80236961Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 80381634Sbrian "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(uh->uh_dport)); 80436961Sbrian loglen += strlen(logbuf + loglen); 80536961Sbrian } 80636961Sbrian break; 80751048Sbrian 8086059Samurai case IPPROTO_TCP: 80981634Sbrian th = (const struct tcphdr *)payload; 81081634Sbrian if (tos == IPTOS_LOWDELAY && bundle->ncp.cfg.urgent.tos) 81150867Sbrian pri++; 81251048Sbrian 81381634Sbrian if (!frag && ncp_IsUrgentTcpPort(&bundle->ncp, ntohs(th->th_sport), 81481634Sbrian ntohs(th->th_dport))) 81550867Sbrian pri++; 81650867Sbrian 81726692Sbrian if (logit && loglen < sizeof logbuf) { 81881634Sbrian len = datalen - (th->th_off << 2); 81928679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 82081634Sbrian "TCP: %s:%d ---> ", ncpaddr_ntoa(&srcaddr), ntohs(th->th_sport)); 82128679Sbrian loglen += strlen(logbuf + loglen); 82228679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 82381634Sbrian "%s:%d", ncpaddr_ntoa(&dstaddr), ntohs(th->th_dport)); 82428679Sbrian loglen += strlen(logbuf + loglen); 8256059Samurai n = 0; 8266059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 82762977Sbrian if (th->th_flags & mask) { 82862977Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 82962977Sbrian loglen += strlen(logbuf + loglen); 83062977Sbrian } 83162977Sbrian n++; 8326059Samurai } 83328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 83462977Sbrian " seq:%lx ack:%lx (%d/%d)", 83562977Sbrian (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 83628679Sbrian loglen += strlen(logbuf + loglen); 8376059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 83881634Sbrian const u_short *sp; 8396059Samurai 84081634Sbrian sp = (const u_short *)(payload + 20); 84162977Sbrian if (ntohs(sp[0]) == 0x0204) { 84262977Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 84362977Sbrian " MSS = %d", ntohs(sp[1])); 84462977Sbrian loglen += strlen(logbuf + loglen); 84562977Sbrian } 8466059Samurai } 8476059Samurai } 8486059Samurai break; 84962778Sbrian 85062778Sbrian default: 85162778Sbrian if (prefix) 85262778Sbrian return -2; 85381634Sbrian 85481634Sbrian if (logit && loglen < sizeof logbuf) { 85581634Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 85681634Sbrian "<%d>: %s ---> ", cproto, ncpaddr_ntoa(&srcaddr)); 85781634Sbrian loglen += strlen(logbuf + loglen); 85881634Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 85981634Sbrian "%s (%d)", ncpaddr_ntoa(&dstaddr), nb); 86081634Sbrian loglen += strlen(logbuf + loglen); 86181634Sbrian } 86281634Sbrian break; 8636059Samurai } 86426692Sbrian 86581634Sbrian if (filter && FilterCheck(packet, family, filter, psecs)) { 86631142Sbrian if (logit) 86736285Sbrian log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 86858033Sbrian result = -1; 8696059Samurai } else { 87036285Sbrian /* Check Keep Alive filter */ 87158033Sbrian if (logit && log_IsKept(LogTCPIP)) { 87262977Sbrian unsigned alivesecs; 87362977Sbrian 87462977Sbrian alivesecs = 0; 87581634Sbrian if (filter && 87681634Sbrian FilterCheck(packet, family, &bundle->filter.alive, &alivesecs)) 87736285Sbrian log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 87862977Sbrian else if (psecs != NULL) { 87962977Sbrian if(*psecs == 0) 88062977Sbrian *psecs = alivesecs; 88162977Sbrian if (*psecs) { 88262977Sbrian if (*psecs != alivesecs) 88398243Sbrian log_Printf(LogTCPIP, "%s - (timeout = %d / ALIVE = %d secs)\n", 88462977Sbrian logbuf, *psecs, alivesecs); 88562977Sbrian else 88662977Sbrian log_Printf(LogTCPIP, "%s - (timeout = %d secs)\n", logbuf, *psecs); 88762977Sbrian } else 88862977Sbrian log_Printf(LogTCPIP, "%s\n", logbuf); 88962977Sbrian } 8906735Samurai } 89158033Sbrian result = pri; 8926059Samurai } 89358033Sbrian 89458776Sbrian if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS)) 89558033Sbrian ip_LogDNS(uh, filter->name); 89658033Sbrian 89758033Sbrian return result; 8986059Samurai} 8996059Samurai 900134789Sbrianstatic size_t 90181634Sbrianip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp, u_int32_t af) 90236285Sbrian{ 903134789Sbrian ssize_t nw; 904134789Sbrian size_t nb; 90531343Sbrian struct tun_data tun; 90656413Sbrian char *data; 90762977Sbrian unsigned secs, alivesecs; 9086059Samurai 90954912Sbrian nb = m_length(bp); 91047168Sbrian if (nb > sizeof tun.data) { 911134833Smarcel log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %zd, max %d)\n", 91247168Sbrian l->name, nb, (int)(sizeof tun.data)); 91354912Sbrian m_freem(bp); 91481634Sbrian return 0; 91547168Sbrian } 91646686Sbrian mbuf_Read(bp, tun.data, nb); 91726031Sbrian 91862977Sbrian secs = 0; 91981634Sbrian if (PacketCheck(bundle, af, tun.data, nb, &bundle->filter.in, 92081634Sbrian NULL, &secs) < 0) 92181634Sbrian return 0; 92226031Sbrian 92362977Sbrian alivesecs = 0; 92481634Sbrian if (!FilterCheck(tun.data, af, &bundle->filter.alive, &alivesecs)) { 92562977Sbrian if (secs == 0) 92662977Sbrian secs = alivesecs; 92762977Sbrian bundle_StartIdleTimer(bundle, secs); 92862977Sbrian } 92926031Sbrian 93056413Sbrian if (bundle->dev.header) { 93181634Sbrian tun.header.family = htonl(af); 93256413Sbrian nb += sizeof tun - sizeof tun.data; 93356413Sbrian data = (char *)&tun; 93456413Sbrian } else 93556413Sbrian data = tun.data; 93656413Sbrian 93756413Sbrian nw = write(bundle->dev.fd, data, nb); 938134789Sbrian if (nw != (ssize_t)nb) { 93946686Sbrian if (nw == -1) 940134833Smarcel log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %s\n", 94147168Sbrian l->name, nb, strerror(errno)); 94246686Sbrian else 943134833Smarcel log_Printf(LogERROR, "ip_Input: %s: wrote %zd, got %zd\n", l->name, nb, 944134833Smarcel nw); 94546686Sbrian } 94636285Sbrian 94781634Sbrian return nb; 9486059Samurai} 9496059Samurai 95081634Sbrianstruct mbuf * 95181634Sbrianipv4_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 9526059Samurai{ 95381634Sbrian int nb; 9546059Samurai 95581634Sbrian if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { 95681634Sbrian log_Printf(LogWARN, "ipv4_Input: IPCP not open - packet dropped\n"); 95781634Sbrian m_freem(bp); 95881634Sbrian return NULL; 95938557Sbrian } 9606059Samurai 96181634Sbrian m_settype(bp, MB_IPIN); 96238544Sbrian 96381634Sbrian nb = ip_Input(bundle, l, bp, AF_INET); 96481634Sbrian ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 96538544Sbrian 96681634Sbrian return NULL; 9677001Samurai} 9687001Samurai 96981634Sbrian#ifndef NOINET6 97081634Sbrianstruct mbuf * 97181634Sbrianipv6_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 9726059Samurai{ 97381634Sbrian int nb; 9746059Samurai 97581897Sbrian if (bundle->ncp.ipv6cp.fsm.state != ST_OPENED) { 97681634Sbrian log_Printf(LogWARN, "ipv6_Input: IPV6CP not open - packet dropped\n"); 97781634Sbrian m_freem(bp); 97881634Sbrian return NULL; 97978411Sbrian } 98078411Sbrian 98181634Sbrian m_settype(bp, MB_IPV6IN); 98236285Sbrian 98381634Sbrian nb = ip_Input(bundle, l, bp, AF_INET6); 98481634Sbrian ipv6cp_AddInOctets(&bundle->ncp.ipv6cp, nb); 98581634Sbrian 98681634Sbrian return NULL; 9876059Samurai} 98881634Sbrian#endif 989