ip.c revision 28679
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 * 2028679Sbrian * $Id: ip.c,v 1.22 1997/06/16 21:20:00 brian Exp $ 218857Srgrimes * 226059Samurai * TODO: 236059Samurai * o Return ICMP message for filterd packet 246059Samurai * and optionaly record it into log. 256059Samurai */ 266059Samurai#include "fsm.h" 276059Samurai#include "lcpproto.h" 286059Samurai#include "hdlc.h" 296059Samurai#include <netinet/in_systm.h> 306059Samurai#include <netinet/ip.h> 316059Samurai#include <netinet/ip_icmp.h> 326059Samurai#include <netinet/udp.h> 336059Samurai#include <netinet/tcp.h> 3413389Sphk#include <arpa/inet.h> 3526031Sbrian#include <alias.h> 3626142Sbrian#include "loadalias.h" 376059Samurai#include "vars.h" 386059Samurai#include "filter.h" 3926516Sbrian#include "mbuf.h" 4026516Sbrian#include "log.h" 416059Samurai 426735Samuraiextern void SendPppFrame(); 436059Samuraiextern void LcpClose(); 446059Samurai 456059Samuraistatic struct pppTimer IdleTimer; 466059Samurai 4728679Sbrianstatic void 4828679SbrianIdleTimeout() 496059Samurai{ 5026516Sbrian LogPrintf(LogPHASE, "Idle timer expired.\n"); 5126098Sbrian reconnect(RECON_FALSE); 526059Samurai LcpClose(); 536059Samurai} 546059Samurai 556059Samurai/* 566059Samurai * Start Idle timer. If timeout is reached, we call LcpClose() to 576059Samurai * close LCP and link. 586059Samurai */ 596059Samuraivoid 606059SamuraiStartIdleTimer() 616059Samurai{ 6228679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 636059Samurai StopTimer(&IdleTimer); 646059Samurai IdleTimer.func = IdleTimeout; 656059Samurai IdleTimer.load = VarIdleTimeout * SECTICKS; 666059Samurai IdleTimer.state = TIMER_STOPPED; 676059Samurai StartTimer(&IdleTimer); 686059Samurai } 696059Samurai} 706059Samurai 716059Samuraivoid 7226516SbrianUpdateIdleTimer() 7326516Sbrian{ 7426516Sbrian if (IdleTimer.state == TIMER_RUNNING) 7526516Sbrian StartIdleTimer(); 7626516Sbrian} 7726516Sbrian 7826516Sbrianvoid 796059SamuraiStopIdleTimer() 806059Samurai{ 816059Samurai StopTimer(&IdleTimer); 826059Samurai} 836059Samurai 846059Samurai/* 856059Samurai * If any IP layer traffic is detected, refresh IdleTimer. 866059Samurai */ 876059Samuraistatic void 886059SamuraiRestartIdleTimer() 896059Samurai{ 9028679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 916059Samurai StartTimer(&IdleTimer); 926059Samurai ipIdleSecs = 0; 936059Samurai } 946059Samurai} 956059Samurai 9613733Sdfrstatic u_short interactive_ports[32] = { 9728679Sbrian 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9828679Sbrian 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 996059Samurai}; 1006059Samurai 10113733Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 1026059Samurai 1036059Samuraistatic char *TcpFlags[] = { 1046059Samurai "FIN", "SYN", "RST", "PSH", "ACK", "URG", 1056059Samurai}; 1066059Samurai 10728679Sbrianstatic char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 10828679Sbrianstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 1096059Samurai 1106059Samuraistatic int 11128679SbrianPortMatch(int op, u_short pport, u_short rport) 1126059Samurai{ 1136059Samurai switch (op) { 11428679Sbrian case OP_EQ: 11528679Sbrian return (pport == rport); 1166059Samurai case OP_GT: 11728679Sbrian return (pport > rport); 1186059Samurai case OP_LT: 11928679Sbrian return (pport < rport); 1206059Samurai default: 12128679Sbrian return (0); 1226059Samurai } 1236059Samurai} 1246059Samurai 1256059Samurai/* 1266059Samurai * Check a packet against with defined filters 1276059Samurai */ 1286059Samuraistatic int 12928679SbrianFilterCheck(struct ip * pip, int direction) 1306059Samurai{ 1316059Samurai struct filterent *fp = Filters[direction]; 1326059Samurai int gotinfo, cproto, estab, n; 1336059Samurai struct tcphdr *th; 1346059Samurai struct udphdr *uh; 1356059Samurai struct icmp *ih; 1366059Samurai char *ptop; 1376059Samurai u_short sport, dport; 1386059Samurai 1396059Samurai if (fp->action) { 1406059Samurai cproto = gotinfo = estab = 0; 1416059Samurai sport = dport = 0; 1426059Samurai for (n = 0; n < MAXFILTERS; n++) { 1436059Samurai if (fp->action) { 14428679Sbrian /* permit fragments on in and out filter */ 14528679Sbrian if ((direction == FL_IN || direction == FL_OUT) && 14628679Sbrian (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 14728679Sbrian return (A_PERMIT); 14828679Sbrian } 14928679Sbrian LogPrintf(LogDEBUG, "rule = %d\n", n); 1506059Samurai if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr 1516059Samurai && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) { 1526059Samurai if (fp->proto) { 1536059Samurai if (!gotinfo) { 15428679Sbrian ptop = (char *) pip + (pip->ip_hl << 2); 1556059Samurai 1566059Samurai switch (pip->ip_p) { 1576059Samurai case IPPROTO_ICMP: 15828679Sbrian cproto = P_ICMP; 15928679Sbrian ih = (struct icmp *) ptop; 16028679Sbrian sport = ih->icmp_type; 16128679Sbrian estab = 1; 1626059Samurai break; 1636059Samurai case IPPROTO_UDP: 16428679Sbrian cproto = P_UDP; 16528679Sbrian uh = (struct udphdr *) ptop; 16628679Sbrian sport = ntohs(uh->uh_sport); 16728679Sbrian dport = ntohs(uh->uh_dport); 1686059Samurai estab = 1; 1696059Samurai break; 1706059Samurai case IPPROTO_TCP: 17128679Sbrian cproto = P_TCP; 17228679Sbrian th = (struct tcphdr *) ptop; 17328679Sbrian sport = ntohs(th->th_sport); 17428679Sbrian dport = ntohs(th->th_dport); 1756059Samurai estab = (th->th_flags & TH_ACK); 17628679Sbrian if (estab == 0) 17728679Sbrian LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 17828679Sbrian th->th_flags, sport, dport); 1796059Samurai break; 1806059Samurai default: 18128679Sbrian return (A_DENY);/* We'll block unknown type of packet */ 1826059Samurai } 1836059Samurai gotinfo = 1; 18428679Sbrian LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 18528679Sbrian " dstop = %d, estab = %d\n", direction, cproto, 18628679Sbrian fp->opt.srcop, fp->opt.dstop, estab); 1876059Samurai } 18826516Sbrian LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 18928679Sbrian " dport = %d\n", n, cproto, sport, dport); 19026516Sbrian LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 19126516Sbrian 1926059Samurai if (cproto == fp->proto) { 1936059Samurai if ((fp->opt.srcop == OP_NONE || 19428679Sbrian PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 19528679Sbrian && 1966059Samurai (fp->opt.dstop == OP_NONE || 19728679Sbrian PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 19828679Sbrian && 1996059Samurai (fp->opt.estab == 0 || estab)) { 20028679Sbrian return (fp->action); 2016059Samurai } 2026059Samurai } 2036059Samurai } else { 2046059Samurai /* Address is mached. Make a decision. */ 20526516Sbrian LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 20628679Sbrian return (fp->action); 2076059Samurai } 2086059Samurai } 2096059Samurai } 2106059Samurai fp++; 2116059Samurai } 21228679Sbrian return (A_DENY); /* No rule is mached. Deny this packet */ 2136059Samurai } 21428679Sbrian return (A_PERMIT); /* No rule is given. Permit this packet */ 2156059Samurai} 2166059Samurai 2176059Samuraistatic void 21828679SbrianIcmpError(struct ip * pip, int code) 2196059Samurai{ 2206059Samurai#ifdef notdef 2216059Samurai struct mbuf *bp; 2226059Samurai 2236059Samurai if (pip->ip_p != IPPROTO_ICMP) { 2246059Samurai bp = mballoc(cnt, MB_IPIN); 2256059Samurai bcopy(ptr, MBUF_CTOP(bp), cnt); 22613733Sdfr SendPppFrame(bp); 2276059Samurai RestartIdleTimer(); 2286059Samurai ipOutOctets += cnt; 2296059Samurai } 2306059Samurai#endif 2316059Samurai} 2326059Samurai 2336059Samurai/* 2346059Samurai * For debugging aid. 2356059Samurai */ 2366059Samuraiint 23728679SbrianPacketCheck(char *cp, int nb, int direction) 2386059Samurai{ 2396059Samurai struct ip *pip; 2406059Samurai struct tcphdr *th; 2416059Samurai struct udphdr *uh; 2426059Samurai struct icmp *icmph; 2436059Samurai char *ptop; 2446059Samurai int mask, len, n; 2456059Samurai int pri = PRI_NORMAL; 24626692Sbrian int logit, loglen; 24726692Sbrian static char logbuf[200]; 2486059Samurai 24926516Sbrian logit = LogIsKept(LogTCPIP); 25026692Sbrian loglen = 0; 2516059Samurai 25228679Sbrian pip = (struct ip *) cp; 2538857Srgrimes 25426692Sbrian if (logit && loglen < sizeof logbuf) { 25528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 25628679Sbrian Direction[direction]); 25728679Sbrian loglen += strlen(logbuf + loglen); 25826692Sbrian } 2596059Samurai ptop = (cp + (pip->ip_hl << 2)); 2606059Samurai 2616059Samurai switch (pip->ip_p) { 2626059Samurai case IPPROTO_ICMP: 26326692Sbrian if (logit && loglen < sizeof logbuf) { 26428679Sbrian icmph = (struct icmp *) ptop; 26528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 26628679Sbrian "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 26728679Sbrian loglen += strlen(logbuf + loglen); 26828679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 26928679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 27028679Sbrian loglen += strlen(logbuf + loglen); 2716059Samurai } 2726059Samurai break; 2736059Samurai case IPPROTO_UDP: 27426692Sbrian if (logit && loglen < sizeof logbuf) { 27528679Sbrian uh = (struct udphdr *) ptop; 27628679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 27728679Sbrian "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 27828679Sbrian loglen += strlen(logbuf + loglen); 27928679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 28028679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 28128679Sbrian loglen += strlen(logbuf + loglen); 2826059Samurai } 2836059Samurai break; 2846059Samurai case IPPROTO_TCP: 28528679Sbrian th = (struct tcphdr *) ptop; 2866059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 2876059Samurai pri = PRI_FAST; 28813733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 2896059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 29028679Sbrian pri = PRI_FAST; 2916059Samurai } 29226692Sbrian if (logit && loglen < sizeof logbuf) { 2936059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 29428679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29528679Sbrian "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 29628679Sbrian loglen += strlen(logbuf + loglen); 29728679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29828679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 29928679Sbrian loglen += strlen(logbuf + loglen); 3006059Samurai n = 0; 3016059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 30226692Sbrian if (th->th_flags & mask) { 30328679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 30428679Sbrian loglen += strlen(logbuf + loglen); 30528679Sbrian } 3066059Samurai n++; 3076059Samurai } 30828679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 30928679Sbrian " seq:%x ack:%x (%d/%d)", 31028679Sbrian ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 31128679Sbrian loglen += strlen(logbuf + loglen); 3126059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 31328679Sbrian u_short *sp; 3146059Samurai 3156059Samurai ptop += 20; 31628679Sbrian sp = (u_short *) ptop; 31726692Sbrian if (ntohs(sp[0]) == 0x0204) { 31828679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 31928679Sbrian " MSS = %d", ntohs(sp[1])); 32028679Sbrian loglen += strlen(logbuf + loglen); 32128679Sbrian } 3226059Samurai } 3236059Samurai } 3246059Samurai break; 3256059Samurai } 32626692Sbrian 32726692Sbrian if (logit) 32826692Sbrian LogPrintf(LogTCPIP, "%s\n", logbuf); 32928679Sbrian 33013733Sdfr if ((FilterCheck(pip, direction) & A_DENY)) { 33126516Sbrian LogPrintf(LogDEBUG, "blocked.\n"); 33228679Sbrian if (direction == 0) 33328679Sbrian IcmpError(pip, pri); 33428679Sbrian return (-1); 3356059Samurai } else { 33628679Sbrian if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 33728679Sbrian ipKeepAlive = FALSE; 3386735Samurai } else { 33928679Sbrian ipKeepAlive = TRUE; 3406735Samurai } 34128679Sbrian return (pri); 3426059Samurai } 3436059Samurai} 3446059Samurai 3456059Samuraivoid 34628679SbrianIpInput(struct mbuf * bp) 34728679Sbrian{ /* IN: Pointer to IP pakcet */ 3486059Samurai u_char *cp; 3496059Samurai struct mbuf *wp; 3506059Samurai int nb, nw; 3516059Samurai u_char tunbuff[MAX_MRU]; 3526059Samurai 3536059Samurai cp = tunbuff; 3546059Samurai nb = 0; 35528679Sbrian for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 3566059Samurai bcopy(MBUF_CTOP(wp), cp, wp->cnt); 3576059Samurai cp += wp->cnt; 3586059Samurai nb += wp->cnt; 3596059Samurai } 3606059Samurai 36120365Sjkh if (mode & MODE_ALIAS) { 36226031Sbrian int iresult; 36326031Sbrian char *fptr; 36426031Sbrian 36526142Sbrian iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff); 36626031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 36726031Sbrian 36826031Sbrian if (nb > MAX_MRU) { 36926516Sbrian LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 37026031Sbrian pfree(bp); 37126031Sbrian return; 37226031Sbrian } 37326031Sbrian if (iresult == PKT_ALIAS_OK 37428679Sbrian || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 37528679Sbrian if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 37628679Sbrian pfree(bp); 37728679Sbrian return; 37826031Sbrian } 37926031Sbrian ipInOctets += nb; 38026031Sbrian 38126031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 38226031Sbrian nw = write(tun_out, tunbuff, nb); 38326031Sbrian if (nw != nb) 38428679Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 38526031Sbrian 38626031Sbrian if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 38728679Sbrian while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) { 38828679Sbrian VarPacketAliasFragmentIn(tunbuff, fptr); 38928679Sbrian nb = ntohs(((struct ip *) fptr)->ip_len); 39028679Sbrian nw = write(tun_out, fptr, nb); 39128679Sbrian if (nw != nb) 39228679Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 39328679Sbrian free(fptr); 39428679Sbrian } 39526031Sbrian } 39628679Sbrian } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 39726031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 39826031Sbrian fptr = malloc(nb); 39926516Sbrian if (fptr == NULL) 40028679Sbrian LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 40126031Sbrian else { 40228679Sbrian memcpy(fptr, tunbuff, nb); 40328679Sbrian VarPacketAliasSaveFragment(fptr); 40426031Sbrian } 40526031Sbrian } 40628679Sbrian } else { /* no aliasing */ 40728679Sbrian if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 40826031Sbrian pfree(bp); 40926031Sbrian return; 41026031Sbrian } 41126031Sbrian ipInOctets += nb; 41226031Sbrian nw = write(tun_out, tunbuff, nb); 41326031Sbrian if (nw != nb) 41426516Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 4156059Samurai } 4166059Samurai pfree(bp); 4176059Samurai 4186059Samurai RestartIdleTimer(); 4196059Samurai} 4206059Samurai 42128679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1]; 4226059Samurai 4236059Samuraivoid 42428679SbrianIpEnqueue(int pri, char *ptr, int count) 4256059Samurai{ 4266059Samurai struct mbuf *bp; 4276059Samurai 4286059Samurai bp = mballoc(count, MB_IPQ); 4296059Samurai bcopy(ptr, MBUF_CTOP(bp), count); 4306059Samurai Enqueue(&IpOutputQueues[pri], bp); 4316059Samurai} 4326059Samurai 4338857Srgrimesint 4347001SamuraiIsIpEnqueued() 4357001Samurai{ 4367001Samurai struct mqueue *queue; 43728679Sbrian int exist = FALSE; 43828679Sbrian 43913733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 44028679Sbrian if (queue->qlen > 0) { 44128679Sbrian exist = TRUE; 44228679Sbrian break; 44328679Sbrian } 4447001Samurai } 44528679Sbrian return (exist); 4467001Samurai} 4477001Samurai 4486059Samuraivoid 4496059SamuraiIpStartOutput() 4506059Samurai{ 4516059Samurai struct mqueue *queue; 4526059Samurai struct mbuf *bp; 45325630Sbrian int cnt; 4546059Samurai 4556059Samurai if (IpcpFsm.state != ST_OPENED) 4566059Samurai return; 45713733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 4586059Samurai if (queue->top) { 4596059Samurai bp = Dequeue(queue); 4606059Samurai if (bp) { 4616059Samurai cnt = plength(bp); 46213733Sdfr SendPppFrame(bp); 4636059Samurai RestartIdleTimer(); 4646059Samurai ipOutOctets += cnt; 46513733Sdfr break; 46628679Sbrian } 4676059Samurai } 4686059Samurai } 4696059Samurai} 470