ip.c revision 30715
16059Samurai/* 26059Samurai * PPP IP Protocol Interface 36059Samurai * 46059Samurai * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 56059Samurai * 66059Samurai * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 76059Samurai * 86059Samurai * Redistribution and use in source and binary forms are permitted 96059Samurai * provided that the above copyright notice and this paragraph are 106059Samurai * duplicated in all such forms and that any documentation, 116059Samurai * advertising materials, and other materials related to such 126059Samurai * distribution and use acknowledge that the software was developed 136059Samurai * by the Internet Initiative Japan. The name of the 146059Samurai * IIJ may not be used to endorse or promote products derived 156059Samurai * from this software without specific prior written permission. 166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198857Srgrimes * 2030715Sbrian * $Id: ip.c,v 1.25 1997/10/04 00:14:39 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o Return ICMP message for filterd packet 246059Samurai * and optionaly record it into log. 256059Samurai */ 2630715Sbrian#include <sys/param.h> 2730715Sbrian#include <netinet/in.h> 286059Samurai#include <netinet/in_systm.h> 296059Samurai#include <netinet/ip.h> 306059Samurai#include <netinet/ip_icmp.h> 316059Samurai#include <netinet/udp.h> 326059Samurai#include <netinet/tcp.h> 3313389Sphk#include <arpa/inet.h> 3430715Sbrian 3526031Sbrian#include <alias.h> 3630092Sbrian#include <errno.h> 3730715Sbrian#include <stdio.h> 3830715Sbrian#include <stdlib.h> 3930715Sbrian#include <string.h> 4030715Sbrian#include <unistd.h> 4130715Sbrian 4230715Sbrian#include "mbuf.h" 4330715Sbrian#include "log.h" 4430715Sbrian#include "defs.h" 4530715Sbrian#include "timer.h" 4630715Sbrian#include "fsm.h" 4730715Sbrian#include "lcpproto.h" 4830715Sbrian#include "hdlc.h" 4926142Sbrian#include "loadalias.h" 5030715Sbrian#include "command.h" 516059Samurai#include "vars.h" 526059Samurai#include "filter.h" 5326516Sbrian#include "log.h" 5429043Sbrian#include "os.h" 5530715Sbrian#include "ipcp.h" 5630715Sbrian#include "vjcomp.h" 5730715Sbrian#include "lcp.h" 5830715Sbrian#include "ip.h" 596059Samurai 606059Samuraistatic struct pppTimer IdleTimer; 616059Samurai 6228679Sbrianstatic void 6328679SbrianIdleTimeout() 646059Samurai{ 6526516Sbrian LogPrintf(LogPHASE, "Idle timer expired.\n"); 6626098Sbrian reconnect(RECON_FALSE); 676059Samurai LcpClose(); 686059Samurai} 696059Samurai 706059Samurai/* 716059Samurai * Start Idle timer. If timeout is reached, we call LcpClose() to 726059Samurai * close LCP and link. 736059Samurai */ 746059Samuraivoid 756059SamuraiStartIdleTimer() 766059Samurai{ 7728679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 786059Samurai StopTimer(&IdleTimer); 796059Samurai IdleTimer.func = IdleTimeout; 806059Samurai IdleTimer.load = VarIdleTimeout * SECTICKS; 816059Samurai IdleTimer.state = TIMER_STOPPED; 826059Samurai StartTimer(&IdleTimer); 836059Samurai } 846059Samurai} 856059Samurai 866059Samuraivoid 8726516SbrianUpdateIdleTimer() 8826516Sbrian{ 8929043Sbrian if (OsLinkIsUp()) 9026516Sbrian StartIdleTimer(); 9126516Sbrian} 9226516Sbrian 9326516Sbrianvoid 946059SamuraiStopIdleTimer() 956059Samurai{ 966059Samurai StopTimer(&IdleTimer); 976059Samurai} 986059Samurai 996059Samurai/* 1006059Samurai * If any IP layer traffic is detected, refresh IdleTimer. 1016059Samurai */ 1026059Samuraistatic void 1036059SamuraiRestartIdleTimer() 1046059Samurai{ 10528679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 1066059Samurai StartTimer(&IdleTimer); 1076059Samurai ipIdleSecs = 0; 1086059Samurai } 1096059Samurai} 1106059Samurai 11113733Sdfrstatic u_short interactive_ports[32] = { 11228679Sbrian 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11328679Sbrian 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 1146059Samurai}; 1156059Samurai 11613733Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 1176059Samurai 1186059Samuraistatic char *TcpFlags[] = { 1196059Samurai "FIN", "SYN", "RST", "PSH", "ACK", "URG", 1206059Samurai}; 1216059Samurai 12228679Sbrianstatic char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 12328679Sbrianstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 1246059Samurai 1256059Samuraistatic int 12628679SbrianPortMatch(int op, u_short pport, u_short rport) 1276059Samurai{ 1286059Samurai switch (op) { 12928679Sbrian case OP_EQ: 13028679Sbrian return (pport == rport); 1316059Samurai case OP_GT: 13228679Sbrian return (pport > rport); 1336059Samurai case OP_LT: 13428679Sbrian return (pport < rport); 1356059Samurai default: 13628679Sbrian return (0); 1376059Samurai } 1386059Samurai} 1396059Samurai 1406059Samurai/* 1416059Samurai * Check a packet against with defined filters 1426059Samurai */ 1436059Samuraistatic int 14428679SbrianFilterCheck(struct ip * pip, int direction) 1456059Samurai{ 1466059Samurai struct filterent *fp = Filters[direction]; 1476059Samurai int gotinfo, cproto, estab, n; 1486059Samurai struct tcphdr *th; 1496059Samurai struct udphdr *uh; 1506059Samurai struct icmp *ih; 1516059Samurai char *ptop; 1526059Samurai u_short sport, dport; 1536059Samurai 1546059Samurai if (fp->action) { 1556059Samurai cproto = gotinfo = estab = 0; 1566059Samurai sport = dport = 0; 1576059Samurai for (n = 0; n < MAXFILTERS; n++) { 1586059Samurai if (fp->action) { 15928679Sbrian /* permit fragments on in and out filter */ 16028679Sbrian if ((direction == FL_IN || direction == FL_OUT) && 16128679Sbrian (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 16228679Sbrian return (A_PERMIT); 16328679Sbrian } 16428679Sbrian LogPrintf(LogDEBUG, "rule = %d\n", n); 1656059Samurai if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr 1666059Samurai && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) { 1676059Samurai if (fp->proto) { 1686059Samurai if (!gotinfo) { 16928679Sbrian ptop = (char *) pip + (pip->ip_hl << 2); 1706059Samurai 1716059Samurai switch (pip->ip_p) { 1726059Samurai case IPPROTO_ICMP: 17328679Sbrian cproto = P_ICMP; 17428679Sbrian ih = (struct icmp *) ptop; 17528679Sbrian sport = ih->icmp_type; 17628679Sbrian estab = 1; 1776059Samurai break; 1786059Samurai case IPPROTO_UDP: 17928679Sbrian cproto = P_UDP; 18028679Sbrian uh = (struct udphdr *) ptop; 18128679Sbrian sport = ntohs(uh->uh_sport); 18228679Sbrian dport = ntohs(uh->uh_dport); 1836059Samurai estab = 1; 1846059Samurai break; 1856059Samurai case IPPROTO_TCP: 18628679Sbrian cproto = P_TCP; 18728679Sbrian th = (struct tcphdr *) ptop; 18828679Sbrian sport = ntohs(th->th_sport); 18928679Sbrian dport = ntohs(th->th_dport); 1906059Samurai estab = (th->th_flags & TH_ACK); 19128679Sbrian if (estab == 0) 19228679Sbrian LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 19328679Sbrian th->th_flags, sport, dport); 1946059Samurai break; 1956059Samurai default: 19628679Sbrian return (A_DENY);/* We'll block unknown type of packet */ 1976059Samurai } 1986059Samurai gotinfo = 1; 19928679Sbrian LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 20028679Sbrian " dstop = %d, estab = %d\n", direction, cproto, 20128679Sbrian fp->opt.srcop, fp->opt.dstop, estab); 2026059Samurai } 20326516Sbrian LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 20428679Sbrian " dport = %d\n", n, cproto, sport, dport); 20526516Sbrian LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 20626516Sbrian 2076059Samurai if (cproto == fp->proto) { 2086059Samurai if ((fp->opt.srcop == OP_NONE || 20928679Sbrian PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 21028679Sbrian && 2116059Samurai (fp->opt.dstop == OP_NONE || 21228679Sbrian PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 21328679Sbrian && 2146059Samurai (fp->opt.estab == 0 || estab)) { 21528679Sbrian return (fp->action); 2166059Samurai } 2176059Samurai } 2186059Samurai } else { 2196059Samurai /* Address is mached. Make a decision. */ 22026516Sbrian LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 22128679Sbrian return (fp->action); 2226059Samurai } 2236059Samurai } 2246059Samurai } 2256059Samurai fp++; 2266059Samurai } 22728679Sbrian return (A_DENY); /* No rule is mached. Deny this packet */ 2286059Samurai } 22928679Sbrian return (A_PERMIT); /* No rule is given. Permit this packet */ 2306059Samurai} 2316059Samurai 2326059Samuraistatic void 23328679SbrianIcmpError(struct ip * pip, int code) 2346059Samurai{ 2356059Samurai#ifdef notdef 2366059Samurai struct mbuf *bp; 2376059Samurai 2386059Samurai if (pip->ip_p != IPPROTO_ICMP) { 2396059Samurai bp = mballoc(cnt, MB_IPIN); 24030715Sbrian memcpy(MBUF_CTOP(bp), ptr, cnt); 24113733Sdfr SendPppFrame(bp); 2426059Samurai RestartIdleTimer(); 2436059Samurai ipOutOctets += cnt; 2446059Samurai } 2456059Samurai#endif 2466059Samurai} 2476059Samurai 2486059Samurai/* 2496059Samurai * For debugging aid. 2506059Samurai */ 2516059Samuraiint 25228679SbrianPacketCheck(char *cp, int nb, int direction) 2536059Samurai{ 2546059Samurai struct ip *pip; 2556059Samurai struct tcphdr *th; 2566059Samurai struct udphdr *uh; 2576059Samurai struct icmp *icmph; 2586059Samurai char *ptop; 2596059Samurai int mask, len, n; 2606059Samurai int pri = PRI_NORMAL; 26126692Sbrian int logit, loglen; 26226692Sbrian static char logbuf[200]; 2636059Samurai 26426516Sbrian logit = LogIsKept(LogTCPIP); 26526692Sbrian loglen = 0; 2666059Samurai 26728679Sbrian pip = (struct ip *) cp; 2688857Srgrimes 26926692Sbrian if (logit && loglen < sizeof logbuf) { 27028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 27128679Sbrian Direction[direction]); 27228679Sbrian loglen += strlen(logbuf + loglen); 27326692Sbrian } 2746059Samurai ptop = (cp + (pip->ip_hl << 2)); 2756059Samurai 2766059Samurai switch (pip->ip_p) { 2776059Samurai case IPPROTO_ICMP: 27826692Sbrian if (logit && loglen < sizeof logbuf) { 27928679Sbrian icmph = (struct icmp *) ptop; 28028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 28128679Sbrian "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 28228679Sbrian loglen += strlen(logbuf + loglen); 28328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 28428679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 28528679Sbrian loglen += strlen(logbuf + loglen); 2866059Samurai } 2876059Samurai break; 2886059Samurai case IPPROTO_UDP: 28926692Sbrian if (logit && loglen < sizeof logbuf) { 29028679Sbrian uh = (struct udphdr *) ptop; 29128679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29228679Sbrian "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 29328679Sbrian loglen += strlen(logbuf + loglen); 29428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29528679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 29628679Sbrian loglen += strlen(logbuf + loglen); 2976059Samurai } 2986059Samurai break; 2996059Samurai case IPPROTO_TCP: 30028679Sbrian th = (struct tcphdr *) ptop; 3016059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 3026059Samurai pri = PRI_FAST; 30313733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 3046059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 30528679Sbrian pri = PRI_FAST; 3066059Samurai } 30726692Sbrian if (logit && loglen < sizeof logbuf) { 3086059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 30928679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 31028679Sbrian "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 31128679Sbrian loglen += strlen(logbuf + loglen); 31228679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 31328679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 31428679Sbrian loglen += strlen(logbuf + loglen); 3156059Samurai n = 0; 3166059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 31726692Sbrian if (th->th_flags & mask) { 31828679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 31928679Sbrian loglen += strlen(logbuf + loglen); 32028679Sbrian } 3216059Samurai n++; 3226059Samurai } 32328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 32428679Sbrian " seq:%x ack:%x (%d/%d)", 32528679Sbrian ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 32628679Sbrian loglen += strlen(logbuf + loglen); 3276059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 32828679Sbrian u_short *sp; 3296059Samurai 3306059Samurai ptop += 20; 33128679Sbrian sp = (u_short *) ptop; 33226692Sbrian if (ntohs(sp[0]) == 0x0204) { 33328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 33428679Sbrian " MSS = %d", ntohs(sp[1])); 33528679Sbrian loglen += strlen(logbuf + loglen); 33628679Sbrian } 3376059Samurai } 3386059Samurai } 3396059Samurai break; 3406059Samurai } 34126692Sbrian 34226692Sbrian if (logit) 34326692Sbrian LogPrintf(LogTCPIP, "%s\n", logbuf); 34428679Sbrian 34513733Sdfr if ((FilterCheck(pip, direction) & A_DENY)) { 34626516Sbrian LogPrintf(LogDEBUG, "blocked.\n"); 34728679Sbrian if (direction == 0) 34828679Sbrian IcmpError(pip, pri); 34928679Sbrian return (-1); 3506059Samurai } else { 35128679Sbrian if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 35230715Sbrian ipKeepAlive = 0; 3536735Samurai } else { 35430715Sbrian ipKeepAlive = 1; 3556735Samurai } 35628679Sbrian return (pri); 3576059Samurai } 3586059Samurai} 3596059Samurai 3606059Samuraivoid 36128679SbrianIpInput(struct mbuf * bp) 36228679Sbrian{ /* IN: Pointer to IP pakcet */ 3636059Samurai u_char *cp; 3646059Samurai struct mbuf *wp; 3656059Samurai int nb, nw; 3666059Samurai u_char tunbuff[MAX_MRU]; 3676059Samurai 3686059Samurai cp = tunbuff; 3696059Samurai nb = 0; 37028679Sbrian for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 37130715Sbrian memcpy(cp, MBUF_CTOP(wp), wp->cnt); 3726059Samurai cp += wp->cnt; 3736059Samurai nb += wp->cnt; 3746059Samurai } 3756059Samurai 37620365Sjkh if (mode & MODE_ALIAS) { 37726031Sbrian int iresult; 37826031Sbrian char *fptr; 37926031Sbrian 38026142Sbrian iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff); 38126031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 38226031Sbrian 38326031Sbrian if (nb > MAX_MRU) { 38426516Sbrian LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 38526031Sbrian pfree(bp); 38626031Sbrian return; 38726031Sbrian } 38826031Sbrian if (iresult == PKT_ALIAS_OK 38928679Sbrian || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 39028679Sbrian if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 39128679Sbrian pfree(bp); 39228679Sbrian return; 39326031Sbrian } 39426031Sbrian ipInOctets += nb; 39526031Sbrian 39626031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 39726031Sbrian nw = write(tun_out, tunbuff, nb); 39826031Sbrian if (nw != nb) 39930092Sbrian if (nw == -1) 40030092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 40130092Sbrian strerror(errno)); 40230092Sbrian else 40330092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 40426031Sbrian 40526031Sbrian if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 40628679Sbrian while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) { 40728679Sbrian VarPacketAliasFragmentIn(tunbuff, fptr); 40828679Sbrian nb = ntohs(((struct ip *) fptr)->ip_len); 40928679Sbrian nw = write(tun_out, fptr, nb); 41028679Sbrian if (nw != nb) 41130092Sbrian if (nw == -1) 41230092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 41330092Sbrian strerror(errno)); 41430092Sbrian else 41530092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 41628679Sbrian free(fptr); 41728679Sbrian } 41826031Sbrian } 41928679Sbrian } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 42026031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 42126031Sbrian fptr = malloc(nb); 42226516Sbrian if (fptr == NULL) 42328679Sbrian LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 42426031Sbrian else { 42528679Sbrian memcpy(fptr, tunbuff, nb); 42628679Sbrian VarPacketAliasSaveFragment(fptr); 42726031Sbrian } 42826031Sbrian } 42928679Sbrian } else { /* no aliasing */ 43028679Sbrian if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 43126031Sbrian pfree(bp); 43226031Sbrian return; 43326031Sbrian } 43426031Sbrian ipInOctets += nb; 43526031Sbrian nw = write(tun_out, tunbuff, nb); 43626031Sbrian if (nw != nb) 43730092Sbrian if (nw == -1) 43830092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 43930092Sbrian else 44030092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 4416059Samurai } 4426059Samurai pfree(bp); 4436059Samurai 4446059Samurai RestartIdleTimer(); 4456059Samurai} 4466059Samurai 44728679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1]; 4486059Samurai 4496059Samuraivoid 45028679SbrianIpEnqueue(int pri, char *ptr, int count) 4516059Samurai{ 4526059Samurai struct mbuf *bp; 4536059Samurai 4546059Samurai bp = mballoc(count, MB_IPQ); 45530715Sbrian memcpy(MBUF_CTOP(bp), ptr, count); 4566059Samurai Enqueue(&IpOutputQueues[pri], bp); 4576059Samurai} 4586059Samurai 45930715Sbrian#if 0 4608857Srgrimesint 4617001SamuraiIsIpEnqueued() 4627001Samurai{ 4637001Samurai struct mqueue *queue; 46430715Sbrian int exist = 0; 46528679Sbrian 46613733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 46728679Sbrian if (queue->qlen > 0) { 46830715Sbrian exist = 1; 46928679Sbrian break; 47028679Sbrian } 4717001Samurai } 47228679Sbrian return (exist); 4737001Samurai} 47430715Sbrian#endif 4757001Samurai 4766059Samuraivoid 4776059SamuraiIpStartOutput() 4786059Samurai{ 4796059Samurai struct mqueue *queue; 4806059Samurai struct mbuf *bp; 48125630Sbrian int cnt; 4826059Samurai 4836059Samurai if (IpcpFsm.state != ST_OPENED) 4846059Samurai return; 48513733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 4866059Samurai if (queue->top) { 4876059Samurai bp = Dequeue(queue); 4886059Samurai if (bp) { 4896059Samurai cnt = plength(bp); 49013733Sdfr SendPppFrame(bp); 4916059Samurai RestartIdleTimer(); 4926059Samurai ipOutOctets += cnt; 49313733Sdfr break; 49428679Sbrian } 4956059Samurai } 4966059Samurai } 4976059Samurai} 498