1af57ed9fSAtsushi Murai /* 2af57ed9fSAtsushi Murai * PPP IP Protocol Interface 3af57ed9fSAtsushi Murai * 4af57ed9fSAtsushi Murai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5af57ed9fSAtsushi Murai * 6af57ed9fSAtsushi Murai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7af57ed9fSAtsushi Murai * 8af57ed9fSAtsushi Murai * Redistribution and use in source and binary forms are permitted 9af57ed9fSAtsushi Murai * provided that the above copyright notice and this paragraph are 10af57ed9fSAtsushi Murai * duplicated in all such forms and that any documentation, 11af57ed9fSAtsushi Murai * advertising materials, and other materials related to such 12af57ed9fSAtsushi Murai * distribution and use acknowledge that the software was developed 13af57ed9fSAtsushi Murai * by the Internet Initiative Japan. The name of the 14af57ed9fSAtsushi Murai * IIJ may not be used to endorse or promote products derived 15af57ed9fSAtsushi Murai * from this software without specific prior written permission. 16af57ed9fSAtsushi Murai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17af57ed9fSAtsushi Murai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18af57ed9fSAtsushi Murai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19af57ed9fSAtsushi Murai * 2097d92980SPeter Wemm * $FreeBSD$ 21af57ed9fSAtsushi Murai * 22af57ed9fSAtsushi Murai * TODO: 23af57ed9fSAtsushi Murai * o Return ICMP message for filterd packet 24af57ed9fSAtsushi Murai * and optionaly record it into log. 25af57ed9fSAtsushi Murai */ 26972a1bcfSBrian Somers #include <sys/param.h> 276a6b4bbbSBrian Somers #include <sys/socket.h> 2875240ed1SBrian Somers #include <netinet/in.h> 29af57ed9fSAtsushi Murai #include <netinet/in_systm.h> 30af57ed9fSAtsushi Murai #include <netinet/ip.h> 31af57ed9fSAtsushi Murai #include <netinet/ip_icmp.h> 32af57ed9fSAtsushi Murai #include <netinet/udp.h> 33af57ed9fSAtsushi Murai #include <netinet/tcp.h> 34ed6a16c1SPoul-Henning Kamp #include <arpa/inet.h> 351fa665f5SBrian Somers #include <sys/un.h> 3675240ed1SBrian Somers 3757fd05c4SBrian Somers #include <errno.h> 3875240ed1SBrian Somers #include <stdio.h> 3975240ed1SBrian Somers #include <string.h> 405d9e6103SBrian Somers #include <termios.h> 4175240ed1SBrian Somers #include <unistd.h> 4275240ed1SBrian Somers 435d9e6103SBrian Somers #include "layer.h" 445d9e6103SBrian Somers #include "proto.h" 45927145beSBrian Somers #include "mbuf.h" 46927145beSBrian Somers #include "log.h" 4775240ed1SBrian Somers #include "defs.h" 4875240ed1SBrian Somers #include "timer.h" 4975240ed1SBrian Somers #include "fsm.h" 50879ed6faSBrian Somers #include "lqr.h" 5175240ed1SBrian Somers #include "hdlc.h" 525828db6dSBrian Somers #include "throughput.h" 535828db6dSBrian Somers #include "iplist.h" 54eaa4df37SBrian Somers #include "slcompress.h" 5575240ed1SBrian Somers #include "ipcp.h" 561ae349f5Scvs2svn #include "filter.h" 572f786681SBrian Somers #include "descriptor.h" 5875240ed1SBrian Somers #include "lcp.h" 593b0f8d2eSBrian Somers #include "ccp.h" 603b0f8d2eSBrian Somers #include "link.h" 613b0f8d2eSBrian Somers #include "mp.h" 62972a1bcfSBrian Somers #ifndef NORADIUS 63972a1bcfSBrian Somers #include "radius.h" 64972a1bcfSBrian Somers #endif 657a6f8720SBrian Somers #include "bundle.h" 666a6b4bbbSBrian Somers #include "tun.h" 6775240ed1SBrian Somers #include "ip.h" 68af57ed9fSAtsushi Murai 6952c9ca19SBrian Somers 7052c9ca19SBrian Somers #define OPCODE_QUERY 0 7152c9ca19SBrian Somers #define OPCODE_IQUERY 1 7252c9ca19SBrian Somers #define OPCODE_STATUS 2 7352c9ca19SBrian Somers 7452c9ca19SBrian Somers struct dns_header { 7552c9ca19SBrian Somers u_short id; 7652c9ca19SBrian Somers unsigned qr : 1; 7752c9ca19SBrian Somers unsigned opcode : 4; 7852c9ca19SBrian Somers unsigned aa : 1; 7952c9ca19SBrian Somers unsigned tc : 1; 8052c9ca19SBrian Somers unsigned rd : 1; 8152c9ca19SBrian Somers unsigned ra : 1; 8252c9ca19SBrian Somers unsigned z : 3; 8352c9ca19SBrian Somers unsigned rcode : 4; 8452c9ca19SBrian Somers u_short qdcount; 8552c9ca19SBrian Somers u_short ancount; 8652c9ca19SBrian Somers u_short nscount; 8752c9ca19SBrian Somers u_short arcount; 88182c898aSBrian Somers }; 89af57ed9fSAtsushi Murai 9052c9ca19SBrian Somers static const char * 9152c9ca19SBrian Somers dns_Qclass2Txt(u_short qclass) 9252c9ca19SBrian Somers { 9352c9ca19SBrian Somers static char failure[6]; 9452c9ca19SBrian Somers struct { 9552c9ca19SBrian Somers u_short id; 9652c9ca19SBrian Somers const char *txt; 9752c9ca19SBrian Somers } qtxt[] = { 9852c9ca19SBrian Somers /* rfc1035 */ 9952c9ca19SBrian Somers { 1, "IN" }, { 2, "CS" }, { 3, "CH" }, { 4, "HS" }, { 255, "*" } 10052c9ca19SBrian Somers }; 10152c9ca19SBrian Somers int f; 10252c9ca19SBrian Somers 10352c9ca19SBrian Somers for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++) 10452c9ca19SBrian Somers if (qtxt[f].id == qclass) 10552c9ca19SBrian Somers return qtxt[f].txt; 10652c9ca19SBrian Somers 107d6d3eeabSBrian Somers return HexStr(qclass, failure, sizeof failure); 10852c9ca19SBrian Somers } 10952c9ca19SBrian Somers 11052c9ca19SBrian Somers static const char * 11152c9ca19SBrian Somers dns_Qtype2Txt(u_short qtype) 11252c9ca19SBrian Somers { 11352c9ca19SBrian Somers static char failure[6]; 11452c9ca19SBrian Somers struct { 11552c9ca19SBrian Somers u_short id; 11652c9ca19SBrian Somers const char *txt; 11752c9ca19SBrian Somers } qtxt[] = { 11852c9ca19SBrian Somers /* rfc1035/rfc1700 */ 11952c9ca19SBrian Somers { 1, "A" }, { 2, "NS" }, { 3, "MD" }, { 4, "MF" }, { 5, "CNAME" }, 12052c9ca19SBrian Somers { 6, "SOA" }, { 7, "MB" }, { 8, "MG" }, { 9, "MR" }, { 10, "NULL" }, 12152c9ca19SBrian Somers { 11, "WKS" }, { 12, "PTR" }, { 13, "HINFO" }, { 14, "MINFO" }, 12252c9ca19SBrian Somers { 15, "MX" }, { 16, "TXT" }, { 17, "RP" }, { 18, "AFSDB" }, 12352c9ca19SBrian Somers { 19, "X25" }, { 20, "ISDN" }, { 21, "RT" }, { 22, "NSAP" }, 12452c9ca19SBrian Somers { 23, "NSAP-PTR" }, { 24, "SIG" }, { 25, "KEY" }, { 26, "PX" }, 12552c9ca19SBrian Somers { 27, "GPOS" }, { 28, "AAAA" }, { 252, "AXFR" }, { 253, "MAILB" }, 12652c9ca19SBrian Somers { 254, "MAILA" }, { 255, "*" } 12752c9ca19SBrian Somers }; 12852c9ca19SBrian Somers int f; 12952c9ca19SBrian Somers 13052c9ca19SBrian Somers for (f = 0; f < sizeof qtxt / sizeof *qtxt; f++) 13152c9ca19SBrian Somers if (qtxt[f].id == qtype) 13252c9ca19SBrian Somers return qtxt[f].txt; 13352c9ca19SBrian Somers 134d6d3eeabSBrian Somers return HexStr(qtype, failure, sizeof failure); 13552c9ca19SBrian Somers } 13652c9ca19SBrian Somers 137cad7e742SBrian Somers static __inline int 138944f7098SBrian Somers PortMatch(int op, u_short pport, u_short rport) 139af57ed9fSAtsushi Murai { 140af57ed9fSAtsushi Murai switch (op) { 141af57ed9fSAtsushi Murai case OP_EQ: 142af57ed9fSAtsushi Murai return (pport == rport); 143af57ed9fSAtsushi Murai case OP_GT: 144af57ed9fSAtsushi Murai return (pport > rport); 145af57ed9fSAtsushi Murai case OP_LT: 146af57ed9fSAtsushi Murai return (pport < rport); 147af57ed9fSAtsushi Murai default: 148af57ed9fSAtsushi Murai return (0); 149af57ed9fSAtsushi Murai } 150af57ed9fSAtsushi Murai } 151af57ed9fSAtsushi Murai 152af57ed9fSAtsushi Murai /* 1535d9e6103SBrian Somers * Check a packet against a defined filter 154cad7e742SBrian Somers * Returns 0 to accept the packet, non-zero to drop the packet 155cad7e742SBrian Somers * 156cad7e742SBrian Somers * If filtering is enabled, the initial fragment of a datagram must 157cad7e742SBrian Somers * contain the complete protocol header, and subsequent fragments 158cad7e742SBrian Somers * must not attempt to over-write it. 159af57ed9fSAtsushi Murai */ 160af57ed9fSAtsushi Murai static int 161cad7e742SBrian Somers FilterCheck(const struct ip *pip, const struct filter *filter) 162af57ed9fSAtsushi Murai { 163cad7e742SBrian Somers int gotinfo; /* true if IP payload decoded */ 164cad7e742SBrian Somers int cproto; /* P_* protocol type if (gotinfo) */ 165cad7e742SBrian Somers int estab, syn, finrst; /* TCP state flags if (gotinfo) */ 166cad7e742SBrian Somers u_short sport, dport; /* src, dest port from packet if (gotinfo) */ 167cad7e742SBrian Somers int n; /* filter rule to process */ 168cad7e742SBrian Somers int len; /* bytes used in dbuff */ 169cad7e742SBrian Somers int didname; /* true if filter header printed */ 170cad7e742SBrian Somers int match; /* true if condition matched */ 171cad7e742SBrian Somers const struct filterent *fp = filter->rule; 1728390b576SBrian Somers char dbuff[100]; 173af57ed9fSAtsushi Murai 174cad7e742SBrian Somers if (fp->f_action == A_NONE) 175cad7e742SBrian Somers return (0); /* No rule is given. Permit this packet */ 176cad7e742SBrian Somers 177cad7e742SBrian Somers /* Deny any packet fragment that tries to over-write the header. 178cad7e742SBrian Somers * Since we no longer have the real header available, punt on the 179cad7e742SBrian Somers * largest normal header - 20 bytes for TCP without options, rounded 180cad7e742SBrian Somers * up to the next possible fragment boundary. Since the smallest 181cad7e742SBrian Somers * `legal' MTU is 576, and the smallest recommended MTU is 296, any 182cad7e742SBrian Somers * fragmentation within this range is dubious at best */ 183cad7e742SBrian Somers len = ntohs(pip->ip_off) & IP_OFFMASK; /* fragment offset */ 184cad7e742SBrian Somers if (len > 0) { /* Not first fragment within datagram */ 185cad7e742SBrian Somers if (len < (24 >> 3)) /* don't allow fragment to over-write header */ 186cad7e742SBrian Somers return (1); 187cad7e742SBrian Somers /* permit fragments on in and out filter */ 1884d9d17feSBrian Somers return (!filter->fragok); 189cad7e742SBrian Somers } 190cad7e742SBrian Somers 19163f98b41SBrian Somers cproto = gotinfo = estab = syn = finrst = didname = 0; 192af57ed9fSAtsushi Murai sport = dport = 0; 193cad7e742SBrian Somers for (n = 0; n < MAXFILTERS; ) { 194cad7e742SBrian Somers if (fp->f_action == A_NONE) { 195cad7e742SBrian Somers n++; 196cad7e742SBrian Somers fp++; 197cad7e742SBrian Somers continue; 198cad7e742SBrian Somers } 1995ca5389aSBrian Somers 200cad7e742SBrian Somers if (!didname) { 201dd7e2610SBrian Somers log_Printf(LogDEBUG, "%s filter:\n", filter->name); 2028390b576SBrian Somers didname = 1; 203cad7e742SBrian Somers } 2048390b576SBrian Somers 205cad7e742SBrian Somers match = 0; 206cad7e742SBrian Somers if (!((pip->ip_src.s_addr ^ fp->f_src.ipaddr.s_addr) & 207cad7e742SBrian Somers fp->f_src.mask.s_addr) && 208cad7e742SBrian Somers !((pip->ip_dst.s_addr ^ fp->f_dst.ipaddr.s_addr) & 209cad7e742SBrian Somers fp->f_dst.mask.s_addr)) { 210cad7e742SBrian Somers if (fp->f_proto != P_NONE) { 211af57ed9fSAtsushi Murai if (!gotinfo) { 212cad7e742SBrian Somers const char *ptop = (const char *) pip + (pip->ip_hl << 2); 213cad7e742SBrian Somers const struct tcphdr *th; 214cad7e742SBrian Somers const struct udphdr *uh; 215cad7e742SBrian Somers const struct icmp *ih; 216cad7e742SBrian Somers int datalen; /* IP datagram length */ 217af57ed9fSAtsushi Murai 218cad7e742SBrian Somers datalen = ntohs(pip->ip_len) - (pip->ip_hl << 2); 219af57ed9fSAtsushi Murai switch (pip->ip_p) { 220af57ed9fSAtsushi Murai case IPPROTO_ICMP: 221944f7098SBrian Somers cproto = P_ICMP; 222cad7e742SBrian Somers if (datalen < 8) /* ICMP must be at least 8 octets */ 223cad7e742SBrian Somers return (1); 224cad7e742SBrian Somers ih = (const struct icmp *) ptop; 225944f7098SBrian Somers sport = ih->icmp_type; 22663f98b41SBrian Somers estab = syn = finrst = -1; 227dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 2288390b576SBrian Somers snprintf(dbuff, sizeof dbuff, "sport = %d", sport); 229af57ed9fSAtsushi Murai break; 230eee772ecSBrian Somers case IPPROTO_IGMP: 2311f9e5fe5SBrian Somers cproto = P_IGMP; 232cad7e742SBrian Somers if (datalen < 8) /* IGMP uses 8-octet messages */ 233cad7e742SBrian Somers return (1); 2341f9e5fe5SBrian Somers estab = syn = finrst = -1; 2351f9e5fe5SBrian Somers sport = ntohs(0); 2361f9e5fe5SBrian Somers break; 23728149effSBrian Somers #ifdef IPPROTO_GRE 23828149effSBrian Somers case IPPROTO_GRE: 23928149effSBrian Somers cproto = P_GRE; 24028149effSBrian Somers if (datalen < 2) /* GRE uses 2-octet+ messages */ 24128149effSBrian Somers return (1); 24228149effSBrian Somers estab = syn = finrst = -1; 24328149effSBrian Somers sport = ntohs(0); 24428149effSBrian Somers break; 24528149effSBrian Somers #endif 24662e85934SBrian Somers #ifdef IPPROTO_OSPFIGP 2472faae814SBrian Somers case IPPROTO_OSPFIGP: 2482faae814SBrian Somers cproto = P_OSPF; 2492faae814SBrian Somers if (datalen < 8) /* IGMP uses 8-octet messages */ 2502faae814SBrian Somers return (1); 2512faae814SBrian Somers estab = syn = finrst = -1; 2522faae814SBrian Somers sport = ntohs(0); 2532faae814SBrian Somers break; 25462e85934SBrian Somers #endif 2551f9e5fe5SBrian Somers case IPPROTO_UDP: 256eee772ecSBrian Somers case IPPROTO_IPIP: 257944f7098SBrian Somers cproto = P_UDP; 258cad7e742SBrian Somers if (datalen < 8) /* UDP header is 8 octets */ 259cad7e742SBrian Somers return (1); 260cad7e742SBrian Somers uh = (const struct udphdr *) ptop; 261944f7098SBrian Somers sport = ntohs(uh->uh_sport); 262944f7098SBrian Somers dport = ntohs(uh->uh_dport); 26363f98b41SBrian Somers estab = syn = finrst = -1; 264dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) 2658390b576SBrian Somers snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d", 2668390b576SBrian Somers sport, dport); 267af57ed9fSAtsushi Murai break; 268af57ed9fSAtsushi Murai case IPPROTO_TCP: 269944f7098SBrian Somers cproto = P_TCP; 270cad7e742SBrian Somers th = (const struct tcphdr *) ptop; 271cad7e742SBrian Somers /* TCP headers are variable length. The following code 272cad7e742SBrian Somers * ensures that the TCP header length isn't de-referenced if 273cad7e742SBrian Somers * the datagram is too short 274cad7e742SBrian Somers */ 275cad7e742SBrian Somers if (datalen < 20 || datalen < (th->th_off << 2)) 276cad7e742SBrian Somers return (1); 277944f7098SBrian Somers sport = ntohs(th->th_sport); 278944f7098SBrian Somers dport = ntohs(th->th_dport); 279af57ed9fSAtsushi Murai estab = (th->th_flags & TH_ACK); 28063f98b41SBrian Somers syn = (th->th_flags & TH_SYN); 28163f98b41SBrian Somers finrst = (th->th_flags & (TH_FIN|TH_RST)); 2822b81c773SBrian Somers if (log_IsKept(LogDEBUG)) { 2832b81c773SBrian Somers if (!estab) 2848390b576SBrian Somers snprintf(dbuff, sizeof dbuff, 2858390b576SBrian Somers "flags = %02x, sport = %d, dport = %d", 286927145beSBrian Somers th->th_flags, sport, dport); 2872b81c773SBrian Somers else 2882b81c773SBrian Somers *dbuff = '\0'; 2892b81c773SBrian Somers } 290af57ed9fSAtsushi Murai break; 291af57ed9fSAtsushi Murai default: 292cad7e742SBrian Somers return (1); /* We'll block unknown type of packet */ 293af57ed9fSAtsushi Murai } 294cad7e742SBrian Somers 295dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) { 2968390b576SBrian Somers if (estab != -1) { 2978390b576SBrian Somers len = strlen(dbuff); 29863f98b41SBrian Somers snprintf(dbuff + len, sizeof dbuff - len, 29963f98b41SBrian Somers ", estab = %d, syn = %d, finrst = %d", 30063f98b41SBrian Somers estab, syn, finrst); 301af57ed9fSAtsushi Murai } 302dd7e2610SBrian Somers log_Printf(LogDEBUG, " Filter: proto = %s, %s\n", 3038390b576SBrian Somers filter_Proto2Nam(cproto), dbuff); 3048390b576SBrian Somers } 3058390b576SBrian Somers gotinfo = 1; 3068390b576SBrian Somers } 307dd7e2610SBrian Somers if (log_IsKept(LogDEBUG)) { 308cad7e742SBrian Somers if (fp->f_srcop != OP_NONE) { 3098390b576SBrian Somers snprintf(dbuff, sizeof dbuff, ", src %s %d", 310cad7e742SBrian Somers filter_Op2Nam(fp->f_srcop), fp->f_srcport); 3118390b576SBrian Somers len = strlen(dbuff); 3128390b576SBrian Somers } else 3138390b576SBrian Somers len = 0; 314cad7e742SBrian Somers if (fp->f_dstop != OP_NONE) { 3158390b576SBrian Somers snprintf(dbuff + len, sizeof dbuff - len, 316cad7e742SBrian Somers ", dst %s %d", filter_Op2Nam(fp->f_dstop), 317cad7e742SBrian Somers fp->f_dstport); 3188390b576SBrian Somers } else if (!len) 3198390b576SBrian Somers *dbuff = '\0'; 3208390b576SBrian Somers 321dd7e2610SBrian Somers log_Printf(LogDEBUG, " rule = %d: Address match, " 3228390b576SBrian Somers "check against proto %s%s, action = %s\n", 323cad7e742SBrian Somers n, filter_Proto2Nam(fp->f_proto), 324cad7e742SBrian Somers dbuff, filter_Action2Nam(fp->f_action)); 3258390b576SBrian Somers } 326927145beSBrian Somers 327cad7e742SBrian Somers if (cproto == fp->f_proto) { 328cad7e742SBrian Somers if ((fp->f_srcop == OP_NONE || 329cad7e742SBrian Somers PortMatch(fp->f_srcop, sport, fp->f_srcport)) && 330cad7e742SBrian Somers (fp->f_dstop == OP_NONE || 331cad7e742SBrian Somers PortMatch(fp->f_dstop, dport, fp->f_dstport)) && 332cad7e742SBrian Somers (fp->f_estab == 0 || estab) && 333cad7e742SBrian Somers (fp->f_syn == 0 || syn) && 334cad7e742SBrian Somers (fp->f_finrst == 0 || finrst)) { 335cad7e742SBrian Somers match = 1; 336af57ed9fSAtsushi Murai } 337af57ed9fSAtsushi Murai } 338af57ed9fSAtsushi Murai } else { 339cad7e742SBrian Somers /* Address is matched and no protocol specified. Make a decision. */ 340dd7e2610SBrian Somers log_Printf(LogDEBUG, " rule = %d: Address match, action = %s\n", n, 341cad7e742SBrian Somers filter_Action2Nam(fp->f_action)); 342cad7e742SBrian Somers match = 1; 343af57ed9fSAtsushi Murai } 3448390b576SBrian Somers } else 345dd7e2610SBrian Somers log_Printf(LogDEBUG, " rule = %d: Address mismatch\n", n); 346cad7e742SBrian Somers 347cad7e742SBrian Somers if (match != fp->f_invert) { 348cad7e742SBrian Somers /* Take specified action */ 349cad7e742SBrian Somers if (fp->f_action < A_NONE) 350cad7e742SBrian Somers fp = &filter->rule[n = fp->f_action]; 351cad7e742SBrian Somers else 352cad7e742SBrian Somers return (fp->f_action != A_PERMIT); 353cad7e742SBrian Somers } else { 354cad7e742SBrian Somers n++; 355af57ed9fSAtsushi Murai fp++; 356af57ed9fSAtsushi Murai } 357af57ed9fSAtsushi Murai } 358cad7e742SBrian Somers return (1); /* No rule is mached. Deny this packet */ 359af57ed9fSAtsushi Murai } 360af57ed9fSAtsushi Murai 3615ca5389aSBrian Somers #ifdef notdef 362af57ed9fSAtsushi Murai static void 363944f7098SBrian Somers IcmpError(struct ip *pip, int code) 364af57ed9fSAtsushi Murai { 365af57ed9fSAtsushi Murai struct mbuf *bp; 366af57ed9fSAtsushi Murai 367af57ed9fSAtsushi Murai if (pip->ip_p != IPPROTO_ICMP) { 36826af0ae9SBrian Somers bp = m_get(m_len, MB_IPIN); 36926af0ae9SBrian Somers memcpy(MBUF_CTOP(bp), ptr, m_len); 370dd7e2610SBrian Somers vj_SendFrame(bp); 37126af0ae9SBrian Somers ipcp_AddOutOctets(m_len); 3721ae349f5Scvs2svn } 373af57ed9fSAtsushi Murai } 374af57ed9fSAtsushi Murai #endif 375af57ed9fSAtsushi Murai 37652c9ca19SBrian Somers static void 37752c9ca19SBrian Somers ip_LogDNS(const struct udphdr *uh, const char *direction) 37852c9ca19SBrian Somers { 37952c9ca19SBrian Somers struct dns_header header; 38052c9ca19SBrian Somers const u_short *pktptr; 38152c9ca19SBrian Somers const u_char *ptr; 38252c9ca19SBrian Somers u_short *hptr; 38352c9ca19SBrian Somers int len; 38452c9ca19SBrian Somers 38552c9ca19SBrian Somers ptr = (const char *)uh + sizeof *uh; 38652c9ca19SBrian Somers len = ntohs(uh->uh_ulen) - sizeof *uh; 38752c9ca19SBrian Somers if (len < sizeof header + 5) /* rfc1024 */ 38852c9ca19SBrian Somers return; 38952c9ca19SBrian Somers 39052c9ca19SBrian Somers pktptr = (const u_short *)ptr; 39152c9ca19SBrian Somers hptr = (u_short *)&header; 39252c9ca19SBrian Somers ptr += sizeof header; 39352c9ca19SBrian Somers len -= sizeof header; 39452c9ca19SBrian Somers 39552c9ca19SBrian Somers while (pktptr < (const u_short *)ptr) { 39652c9ca19SBrian Somers *hptr++ = ntohs(*pktptr); /* Careful of macro side-effects ! */ 39752c9ca19SBrian Somers pktptr++; 39852c9ca19SBrian Somers } 39952c9ca19SBrian Somers 40052c9ca19SBrian Somers if (header.opcode == OPCODE_QUERY && header.qr == 0) { 40152c9ca19SBrian Somers /* rfc1035 */ 40252c9ca19SBrian Somers char name[MAXHOSTNAMELEN + 1], *n; 40352c9ca19SBrian Somers const char *qtype, *qclass; 40452c9ca19SBrian Somers const u_char *end; 40552c9ca19SBrian Somers 40652c9ca19SBrian Somers n = name; 40752c9ca19SBrian Somers end = ptr + len - 4; 40852c9ca19SBrian Somers if (end - ptr > MAXHOSTNAMELEN) 40952c9ca19SBrian Somers end = ptr + MAXHOSTNAMELEN; 41052c9ca19SBrian Somers while (ptr < end) { 41152c9ca19SBrian Somers len = *ptr++; 41252c9ca19SBrian Somers if (len > end - ptr) 41352c9ca19SBrian Somers len = end - ptr; 41452c9ca19SBrian Somers if (n != name) 41552c9ca19SBrian Somers *n++ = '.'; 41652c9ca19SBrian Somers memcpy(n, ptr, len); 41752c9ca19SBrian Somers ptr += len; 41852c9ca19SBrian Somers n += len; 41952c9ca19SBrian Somers } 42052c9ca19SBrian Somers *n = '\0'; 42152c9ca19SBrian Somers qtype = dns_Qtype2Txt(ntohs(*(const u_short *)end)); 42252c9ca19SBrian Somers qclass = dns_Qclass2Txt(ntohs(*(const u_short *)(end + 2))); 42352c9ca19SBrian Somers 42452c9ca19SBrian Somers log_Printf(LogDNS, "%sbound query %s %s %s\n", 42552c9ca19SBrian Somers direction, qclass, qtype, name); 42652c9ca19SBrian Somers } 42752c9ca19SBrian Somers } 42852c9ca19SBrian Somers 429af57ed9fSAtsushi Murai /* 430af57ed9fSAtsushi Murai * For debugging aid. 431af57ed9fSAtsushi Murai */ 432af57ed9fSAtsushi Murai int 4335ca5389aSBrian Somers PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter) 434af57ed9fSAtsushi Murai { 43552c9ca19SBrian Somers static const char *const TcpFlags[] = { 43652c9ca19SBrian Somers "FIN", "SYN", "RST", "PSH", "ACK", "URG" 43752c9ca19SBrian Somers }; 438af57ed9fSAtsushi Murai struct ip *pip; 439af57ed9fSAtsushi Murai struct tcphdr *th; 440af57ed9fSAtsushi Murai struct udphdr *uh; 441af57ed9fSAtsushi Murai struct icmp *icmph; 442af57ed9fSAtsushi Murai char *ptop; 44352c9ca19SBrian Somers int mask, len, n, pri, logit, loglen, result; 444d93d3a9cSBrian Somers char logbuf[200]; 445af57ed9fSAtsushi Murai 446b565321aSBrian Somers logit = (log_IsKept(LogTCPIP) || log_IsKept(LogDNS)) && 447b565321aSBrian Somers (!filter || filter->logok); 44855a8cdeaSBrian Somers loglen = 0; 44952c9ca19SBrian Somers pri = 0; 450af57ed9fSAtsushi Murai 451af57ed9fSAtsushi Murai pip = (struct ip *)cp; 45252c9ca19SBrian Somers uh = NULL; 453af57ed9fSAtsushi Murai 45455a8cdeaSBrian Somers if (logit && loglen < sizeof logbuf) { 455b565321aSBrian Somers if (filter) 4565ca5389aSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name); 457b565321aSBrian Somers else 458b565321aSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, " "); 45955a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 46055a8cdeaSBrian Somers } 461af57ed9fSAtsushi Murai ptop = (cp + (pip->ip_hl << 2)); 462af57ed9fSAtsushi Murai 463af57ed9fSAtsushi Murai switch (pip->ip_p) { 464af57ed9fSAtsushi Murai case IPPROTO_ICMP: 46555a8cdeaSBrian Somers if (logit && loglen < sizeof logbuf) { 466af57ed9fSAtsushi Murai icmph = (struct icmp *) ptop; 46755a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 46855a8cdeaSBrian Somers "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 46955a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 47055a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 47155a8cdeaSBrian Somers "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 47255a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 473af57ed9fSAtsushi Murai } 474af57ed9fSAtsushi Murai break; 475da477886SBrian Somers 476af57ed9fSAtsushi Murai case IPPROTO_UDP: 477af57ed9fSAtsushi Murai uh = (struct udphdr *) ptop; 478da477886SBrian Somers if (pip->ip_tos == IPTOS_LOWDELAY) 479da477886SBrian Somers pri++; 480da477886SBrian Somers 481da477886SBrian Somers if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 && 482da477886SBrian Somers ipcp_IsUrgentUdpPort(&bundle->ncp.ipcp, ntohs(uh->uh_sport), 483da477886SBrian Somers ntohs(uh->uh_dport))) 484da477886SBrian Somers pri++; 485da477886SBrian Somers 486da477886SBrian Somers if (logit && loglen < sizeof logbuf) { 48755a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 48855a8cdeaSBrian Somers "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 48955a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 49055a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 49155a8cdeaSBrian Somers "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 49255a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 493af57ed9fSAtsushi Murai } 494af57ed9fSAtsushi Murai break; 495da477886SBrian Somers 49628149effSBrian Somers #ifdef IPPROTO_GRE 49728149effSBrian Somers case IPPROTO_GRE: 49828149effSBrian Somers if (logit && loglen < sizeof logbuf) { 49928149effSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 50028149effSBrian Somers "GRE: %s ---> ", inet_ntoa(pip->ip_src)); 50128149effSBrian Somers loglen += strlen(logbuf + loglen); 50228149effSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 50328149effSBrian Somers "%s", inet_ntoa(pip->ip_dst)); 50428149effSBrian Somers loglen += strlen(logbuf + loglen); 50528149effSBrian Somers } 50628149effSBrian Somers break; 50728149effSBrian Somers #endif 50828149effSBrian Somers 50962e85934SBrian Somers #ifdef IPPROTO_OSPFIGP 5102faae814SBrian Somers case IPPROTO_OSPFIGP: 5112faae814SBrian Somers if (logit && loglen < sizeof logbuf) { 5122faae814SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 5132faae814SBrian Somers "OSPF: %s ---> ", inet_ntoa(pip->ip_src)); 5142faae814SBrian Somers loglen += strlen(logbuf + loglen); 5152faae814SBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 5162faae814SBrian Somers "%s", inet_ntoa(pip->ip_dst)); 5172faae814SBrian Somers loglen += strlen(logbuf + loglen); 5182faae814SBrian Somers } 5192faae814SBrian Somers break; 52062e85934SBrian Somers #endif 521da477886SBrian Somers 522eee772ecSBrian Somers case IPPROTO_IPIP: 523eee772ecSBrian Somers if (logit && loglen < sizeof logbuf) { 524eee772ecSBrian Somers uh = (struct udphdr *) ptop; 525eee772ecSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 526eee772ecSBrian Somers "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 527eee772ecSBrian Somers loglen += strlen(logbuf + loglen); 528eee772ecSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 529eee772ecSBrian Somers "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 530eee772ecSBrian Somers loglen += strlen(logbuf + loglen); 531eee772ecSBrian Somers } 532eee772ecSBrian Somers break; 533da477886SBrian Somers 534eee772ecSBrian Somers case IPPROTO_IGMP: 535eee772ecSBrian Somers if (logit && loglen < sizeof logbuf) { 536eee772ecSBrian Somers uh = (struct udphdr *) ptop; 537eee772ecSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 538eee772ecSBrian Somers "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 539eee772ecSBrian Somers loglen += strlen(logbuf + loglen); 540eee772ecSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 541eee772ecSBrian Somers "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 542eee772ecSBrian Somers loglen += strlen(logbuf + loglen); 543eee772ecSBrian Somers } 544eee772ecSBrian Somers break; 545da477886SBrian Somers 546af57ed9fSAtsushi Murai case IPPROTO_TCP: 547af57ed9fSAtsushi Murai th = (struct tcphdr *) ptop; 548af57ed9fSAtsushi Murai if (pip->ip_tos == IPTOS_LOWDELAY) 549442f8495SBrian Somers pri++; 550da477886SBrian Somers 551da477886SBrian Somers if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0 && 552da477886SBrian Somers ipcp_IsUrgentTcpPort(&bundle->ncp.ipcp, ntohs(th->th_sport), 553442f8495SBrian Somers ntohs(th->th_dport))) 554442f8495SBrian Somers pri++; 555442f8495SBrian Somers 55655a8cdeaSBrian Somers if (logit && loglen < sizeof logbuf) { 557af57ed9fSAtsushi Murai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 55855a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 55955a8cdeaSBrian Somers "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 56055a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 56155a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 56255a8cdeaSBrian Somers "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 56355a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 564af57ed9fSAtsushi Murai n = 0; 565af57ed9fSAtsushi Murai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 56655a8cdeaSBrian Somers if (th->th_flags & mask) { 56755a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 56855a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 56955a8cdeaSBrian Somers } 570af57ed9fSAtsushi Murai n++; 571af57ed9fSAtsushi Murai } 57255a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 5733a2e4f62SBrian Somers " seq:%lx ack:%lx (%d/%d)", 5743a2e4f62SBrian Somers (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb); 57555a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 576af57ed9fSAtsushi Murai if ((th->th_flags & TH_SYN) && nb > 40) { 577af57ed9fSAtsushi Murai u_short *sp; 578af57ed9fSAtsushi Murai 579af57ed9fSAtsushi Murai ptop += 20; 580af57ed9fSAtsushi Murai sp = (u_short *) ptop; 58155a8cdeaSBrian Somers if (ntohs(sp[0]) == 0x0204) { 58255a8cdeaSBrian Somers snprintf(logbuf + loglen, sizeof logbuf - loglen, 58355a8cdeaSBrian Somers " MSS = %d", ntohs(sp[1])); 58455a8cdeaSBrian Somers loglen += strlen(logbuf + loglen); 58555a8cdeaSBrian Somers } 586af57ed9fSAtsushi Murai } 587af57ed9fSAtsushi Murai } 588af57ed9fSAtsushi Murai break; 589af57ed9fSAtsushi Murai } 59076bd0c0aSDoug Rabson 591b565321aSBrian Somers if (filter && FilterCheck(pip, filter)) { 592710e9c29SBrian Somers if (logit) 593dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf); 5945ca5389aSBrian Somers #ifdef notdef 595944f7098SBrian Somers if (direction == 0) 596944f7098SBrian Somers IcmpError(pip, pri); 5975ca5389aSBrian Somers #endif 59852c9ca19SBrian Somers result = -1; 599af57ed9fSAtsushi Murai } else { 6005ca5389aSBrian Somers /* Check Keep Alive filter */ 60152c9ca19SBrian Somers if (logit && log_IsKept(LogTCPIP)) { 602b565321aSBrian Somers if (filter && FilterCheck(pip, &bundle->filter.alive)) 603dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 6041e991daaSBrian Somers else 605dd7e2610SBrian Somers log_Printf(LogTCPIP, "%s\n", logbuf); 60653c9f6c0SAtsushi Murai } 60752c9ca19SBrian Somers result = pri; 608af57ed9fSAtsushi Murai } 60952c9ca19SBrian Somers 610b565321aSBrian Somers if (filter && uh && ntohs(uh->uh_dport) == 53 && log_IsKept(LogDNS)) 61152c9ca19SBrian Somers ip_LogDNS(uh, filter->name); 61252c9ca19SBrian Somers 61352c9ca19SBrian Somers return result; 614af57ed9fSAtsushi Murai } 615af57ed9fSAtsushi Murai 6165d9e6103SBrian Somers struct mbuf * 6175d9e6103SBrian Somers ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp) 6187a6f8720SBrian Somers { 619af57ed9fSAtsushi Murai int nb, nw; 620b6e82f33SBrian Somers struct tun_data tun; 6215d9e6103SBrian Somers struct ip *pip; 6223a7b6d76SBrian Somers char *data; 6235d9e6103SBrian Somers 6245d9e6103SBrian Somers if (bundle->ncp.ipcp.fsm.state != ST_OPENED) { 6255d9e6103SBrian Somers log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n"); 62626af0ae9SBrian Somers m_freem(bp); 6275d9e6103SBrian Somers return NULL; 6285d9e6103SBrian Somers } 629af57ed9fSAtsushi Murai 63026af0ae9SBrian Somers m_settype(bp, MB_IPIN); 63126af0ae9SBrian Somers nb = m_length(bp); 63276d98538SBrian Somers if (nb > sizeof tun.data) { 63376d98538SBrian Somers log_Printf(LogWARN, "ip_Input: %s: Packet too large (got %d, max %d)\n", 63476d98538SBrian Somers l->name, nb, (int)(sizeof tun.data)); 63526af0ae9SBrian Somers m_freem(bp); 63676d98538SBrian Somers return NULL; 63776d98538SBrian Somers } 6385d9e6103SBrian Somers mbuf_Read(bp, tun.data, nb); 639af57ed9fSAtsushi Murai 6405d9e6103SBrian Somers if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) 6415d9e6103SBrian Somers return NULL; 6426db75539SBrian Somers 6435d9e6103SBrian Somers pip = (struct ip *)tun.data; 644cad7e742SBrian Somers if (!FilterCheck(pip, &bundle->filter.alive)) 6451e991daaSBrian Somers bundle_StartIdleTimer(bundle); 6461e991daaSBrian Somers 6475828db6dSBrian Somers ipcp_AddInOctets(&bundle->ncp.ipcp, nb); 6481e991daaSBrian Somers 6493a7b6d76SBrian Somers if (bundle->dev.header) { 6503a7b6d76SBrian Somers tun.family = htonl(AF_INET); 65170ee81ffSBrian Somers nb += sizeof tun - sizeof tun.data; 6523a7b6d76SBrian Somers data = (char *)&tun; 6533a7b6d76SBrian Somers } else 6543a7b6d76SBrian Somers data = tun.data; 6553a7b6d76SBrian Somers 6563a7b6d76SBrian Somers nw = write(bundle->dev.fd, data, nb); 657c4c4aaacSBrian Somers if (nw != nb) { 65857fd05c4SBrian Somers if (nw == -1) 65976d98538SBrian Somers log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %s\n", 66076d98538SBrian Somers l->name, nb, strerror(errno)); 66157fd05c4SBrian Somers else 66276d98538SBrian Somers log_Printf(LogERROR, "ip_Input: %s: wrote %d, got %d\n", l->name, nb, nw); 6636db75539SBrian Somers } 6645d9e6103SBrian Somers 6655d9e6103SBrian Somers return NULL; 666af57ed9fSAtsushi Murai } 667af57ed9fSAtsushi Murai 668af57ed9fSAtsushi Murai void 6695a72b6edSBrian Somers ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count) 670af57ed9fSAtsushi Murai { 671af57ed9fSAtsushi Murai struct mbuf *bp; 672af57ed9fSAtsushi Murai 673442f8495SBrian Somers if (pri < 0 || pri >= IPCP_QUEUES(ipcp)) 6745a72b6edSBrian Somers log_Printf(LogERROR, "Can't store in ip queue %d\n", pri); 6755a72b6edSBrian Somers else { 6765d9e6103SBrian Somers /* 6775d9e6103SBrian Somers * We allocate an extra 6 bytes, four at the front and two at the end. 6785d9e6103SBrian Somers * This is an optimisation so that we need to do less work in 67926af0ae9SBrian Somers * m_prepend() in acf_LayerPush() and proto_LayerPush() and 6805d9e6103SBrian Somers * appending in hdlc_LayerPush(). 6815d9e6103SBrian Somers */ 68226af0ae9SBrian Somers bp = m_get(count + 6, MB_IPOUT); 68326af0ae9SBrian Somers bp->m_offset += 4; 68426af0ae9SBrian Somers bp->m_len -= 6; 68575240ed1SBrian Somers memcpy(MBUF_CTOP(bp), ptr, count); 68626af0ae9SBrian Somers m_enqueue(ipcp->Queue + pri, bp); 6875a72b6edSBrian Somers } 688af57ed9fSAtsushi Murai } 689af57ed9fSAtsushi Murai 6906f8e9f0aSBrian Somers void 6915a72b6edSBrian Somers ip_DeleteQueue(struct ipcp *ipcp) 6926f8e9f0aSBrian Somers { 6936f8e9f0aSBrian Somers struct mqueue *queue; 6946f8e9f0aSBrian Somers 695442f8495SBrian Somers for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++) 6966f8e9f0aSBrian Somers while (queue->top) 69726af0ae9SBrian Somers m_freem(m_dequeue(queue)); 6986f8e9f0aSBrian Somers } 6996f8e9f0aSBrian Somers 70026af0ae9SBrian Somers size_t 7015a72b6edSBrian Somers ip_QueueLen(struct ipcp *ipcp) 70284b8a6ebSAtsushi Murai { 70384b8a6ebSAtsushi Murai struct mqueue *queue; 70426af0ae9SBrian Somers size_t result; 705944f7098SBrian Somers 70626af0ae9SBrian Somers result = 0; 707442f8495SBrian Somers for (queue = ipcp->Queue; queue < ipcp->Queue + IPCP_QUEUES(ipcp); queue++) 70826af0ae9SBrian Somers result += queue->len; 70984b8a6ebSAtsushi Murai 710f4768038SBrian Somers return result; 7111ae349f5Scvs2svn } 7121ae349f5Scvs2svn 7133b0f8d2eSBrian Somers int 7145d9e6103SBrian Somers ip_PushPacket(struct link *l, struct bundle *bundle) 715af57ed9fSAtsushi Murai { 7165a72b6edSBrian Somers struct ipcp *ipcp = &bundle->ncp.ipcp; 717af57ed9fSAtsushi Murai struct mqueue *queue; 718af57ed9fSAtsushi Murai struct mbuf *bp; 7195d9e6103SBrian Somers struct ip *pip; 72026af0ae9SBrian Somers int m_len; 721af57ed9fSAtsushi Murai 7225a72b6edSBrian Somers if (ipcp->fsm.state != ST_OPENED) 7233b0f8d2eSBrian Somers return 0; 7241e991daaSBrian Somers 725442f8495SBrian Somers queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1; 726442f8495SBrian Somers do { 727af57ed9fSAtsushi Murai if (queue->top) { 72826af0ae9SBrian Somers bp = m_pullup(m_dequeue(queue)); 72926af0ae9SBrian Somers m_len = m_length(bp); 7305d9e6103SBrian Somers pip = (struct ip *)MBUF_CTOP(bp); 731cad7e742SBrian Somers if (!FilterCheck(pip, &bundle->filter.alive)) 732ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 733442f8495SBrian Somers link_PushPacket(l, bp, bundle, 0, PROTO_IP); 73426af0ae9SBrian Somers ipcp_AddOutOctets(ipcp, m_len); 7353b0f8d2eSBrian Somers return 1; 736af57ed9fSAtsushi Murai } 737442f8495SBrian Somers } while (queue-- != ipcp->Queue); 7381e991daaSBrian Somers 7393b0f8d2eSBrian Somers return 0; 740af57ed9fSAtsushi Murai } 741