ip.c revision 30092
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 * 2030092Sbrian * $Id: ip.c,v 1.24 1997/09/03 00:40:49 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> 3630092Sbrian#include <errno.h> 3726142Sbrian#include "loadalias.h" 386059Samurai#include "vars.h" 396059Samurai#include "filter.h" 4026516Sbrian#include "mbuf.h" 4126516Sbrian#include "log.h" 4229043Sbrian#include "os.h" 436059Samurai 446735Samuraiextern void SendPppFrame(); 456059Samuraiextern void LcpClose(); 466059Samurai 476059Samuraistatic struct pppTimer IdleTimer; 486059Samurai 4928679Sbrianstatic void 5028679SbrianIdleTimeout() 516059Samurai{ 5226516Sbrian LogPrintf(LogPHASE, "Idle timer expired.\n"); 5326098Sbrian reconnect(RECON_FALSE); 546059Samurai LcpClose(); 556059Samurai} 566059Samurai 576059Samurai/* 586059Samurai * Start Idle timer. If timeout is reached, we call LcpClose() to 596059Samurai * close LCP and link. 606059Samurai */ 616059Samuraivoid 626059SamuraiStartIdleTimer() 636059Samurai{ 6428679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 656059Samurai StopTimer(&IdleTimer); 666059Samurai IdleTimer.func = IdleTimeout; 676059Samurai IdleTimer.load = VarIdleTimeout * SECTICKS; 686059Samurai IdleTimer.state = TIMER_STOPPED; 696059Samurai StartTimer(&IdleTimer); 706059Samurai } 716059Samurai} 726059Samurai 736059Samuraivoid 7426516SbrianUpdateIdleTimer() 7526516Sbrian{ 7629043Sbrian if (OsLinkIsUp()) 7726516Sbrian StartIdleTimer(); 7826516Sbrian} 7926516Sbrian 8026516Sbrianvoid 816059SamuraiStopIdleTimer() 826059Samurai{ 836059Samurai StopTimer(&IdleTimer); 846059Samurai} 856059Samurai 866059Samurai/* 876059Samurai * If any IP layer traffic is detected, refresh IdleTimer. 886059Samurai */ 896059Samuraistatic void 906059SamuraiRestartIdleTimer() 916059Samurai{ 9228679Sbrian if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 936059Samurai StartTimer(&IdleTimer); 946059Samurai ipIdleSecs = 0; 956059Samurai } 966059Samurai} 976059Samurai 9813733Sdfrstatic u_short interactive_ports[32] = { 9928679Sbrian 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10028679Sbrian 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 1016059Samurai}; 1026059Samurai 10313733Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 1046059Samurai 1056059Samuraistatic char *TcpFlags[] = { 1066059Samurai "FIN", "SYN", "RST", "PSH", "ACK", "URG", 1076059Samurai}; 1086059Samurai 10928679Sbrianstatic char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 11028679Sbrianstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 1116059Samurai 1126059Samuraistatic int 11328679SbrianPortMatch(int op, u_short pport, u_short rport) 1146059Samurai{ 1156059Samurai switch (op) { 11628679Sbrian case OP_EQ: 11728679Sbrian return (pport == rport); 1186059Samurai case OP_GT: 11928679Sbrian return (pport > rport); 1206059Samurai case OP_LT: 12128679Sbrian return (pport < rport); 1226059Samurai default: 12328679Sbrian return (0); 1246059Samurai } 1256059Samurai} 1266059Samurai 1276059Samurai/* 1286059Samurai * Check a packet against with defined filters 1296059Samurai */ 1306059Samuraistatic int 13128679SbrianFilterCheck(struct ip * pip, int direction) 1326059Samurai{ 1336059Samurai struct filterent *fp = Filters[direction]; 1346059Samurai int gotinfo, cproto, estab, n; 1356059Samurai struct tcphdr *th; 1366059Samurai struct udphdr *uh; 1376059Samurai struct icmp *ih; 1386059Samurai char *ptop; 1396059Samurai u_short sport, dport; 1406059Samurai 1416059Samurai if (fp->action) { 1426059Samurai cproto = gotinfo = estab = 0; 1436059Samurai sport = dport = 0; 1446059Samurai for (n = 0; n < MAXFILTERS; n++) { 1456059Samurai if (fp->action) { 14628679Sbrian /* permit fragments on in and out filter */ 14728679Sbrian if ((direction == FL_IN || direction == FL_OUT) && 14828679Sbrian (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 14928679Sbrian return (A_PERMIT); 15028679Sbrian } 15128679Sbrian LogPrintf(LogDEBUG, "rule = %d\n", n); 1526059Samurai if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr 1536059Samurai && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) { 1546059Samurai if (fp->proto) { 1556059Samurai if (!gotinfo) { 15628679Sbrian ptop = (char *) pip + (pip->ip_hl << 2); 1576059Samurai 1586059Samurai switch (pip->ip_p) { 1596059Samurai case IPPROTO_ICMP: 16028679Sbrian cproto = P_ICMP; 16128679Sbrian ih = (struct icmp *) ptop; 16228679Sbrian sport = ih->icmp_type; 16328679Sbrian estab = 1; 1646059Samurai break; 1656059Samurai case IPPROTO_UDP: 16628679Sbrian cproto = P_UDP; 16728679Sbrian uh = (struct udphdr *) ptop; 16828679Sbrian sport = ntohs(uh->uh_sport); 16928679Sbrian dport = ntohs(uh->uh_dport); 1706059Samurai estab = 1; 1716059Samurai break; 1726059Samurai case IPPROTO_TCP: 17328679Sbrian cproto = P_TCP; 17428679Sbrian th = (struct tcphdr *) ptop; 17528679Sbrian sport = ntohs(th->th_sport); 17628679Sbrian dport = ntohs(th->th_dport); 1776059Samurai estab = (th->th_flags & TH_ACK); 17828679Sbrian if (estab == 0) 17928679Sbrian LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 18028679Sbrian th->th_flags, sport, dport); 1816059Samurai break; 1826059Samurai default: 18328679Sbrian return (A_DENY);/* We'll block unknown type of packet */ 1846059Samurai } 1856059Samurai gotinfo = 1; 18628679Sbrian LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 18728679Sbrian " dstop = %d, estab = %d\n", direction, cproto, 18828679Sbrian fp->opt.srcop, fp->opt.dstop, estab); 1896059Samurai } 19026516Sbrian LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 19128679Sbrian " dport = %d\n", n, cproto, sport, dport); 19226516Sbrian LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 19326516Sbrian 1946059Samurai if (cproto == fp->proto) { 1956059Samurai if ((fp->opt.srcop == OP_NONE || 19628679Sbrian PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 19728679Sbrian && 1986059Samurai (fp->opt.dstop == OP_NONE || 19928679Sbrian PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 20028679Sbrian && 2016059Samurai (fp->opt.estab == 0 || estab)) { 20228679Sbrian return (fp->action); 2036059Samurai } 2046059Samurai } 2056059Samurai } else { 2066059Samurai /* Address is mached. Make a decision. */ 20726516Sbrian LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 20828679Sbrian return (fp->action); 2096059Samurai } 2106059Samurai } 2116059Samurai } 2126059Samurai fp++; 2136059Samurai } 21428679Sbrian return (A_DENY); /* No rule is mached. Deny this packet */ 2156059Samurai } 21628679Sbrian return (A_PERMIT); /* No rule is given. Permit this packet */ 2176059Samurai} 2186059Samurai 2196059Samuraistatic void 22028679SbrianIcmpError(struct ip * pip, int code) 2216059Samurai{ 2226059Samurai#ifdef notdef 2236059Samurai struct mbuf *bp; 2246059Samurai 2256059Samurai if (pip->ip_p != IPPROTO_ICMP) { 2266059Samurai bp = mballoc(cnt, MB_IPIN); 2276059Samurai bcopy(ptr, MBUF_CTOP(bp), cnt); 22813733Sdfr SendPppFrame(bp); 2296059Samurai RestartIdleTimer(); 2306059Samurai ipOutOctets += cnt; 2316059Samurai } 2326059Samurai#endif 2336059Samurai} 2346059Samurai 2356059Samurai/* 2366059Samurai * For debugging aid. 2376059Samurai */ 2386059Samuraiint 23928679SbrianPacketCheck(char *cp, int nb, int direction) 2406059Samurai{ 2416059Samurai struct ip *pip; 2426059Samurai struct tcphdr *th; 2436059Samurai struct udphdr *uh; 2446059Samurai struct icmp *icmph; 2456059Samurai char *ptop; 2466059Samurai int mask, len, n; 2476059Samurai int pri = PRI_NORMAL; 24826692Sbrian int logit, loglen; 24926692Sbrian static char logbuf[200]; 2506059Samurai 25126516Sbrian logit = LogIsKept(LogTCPIP); 25226692Sbrian loglen = 0; 2536059Samurai 25428679Sbrian pip = (struct ip *) cp; 2558857Srgrimes 25626692Sbrian if (logit && loglen < sizeof logbuf) { 25728679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 25828679Sbrian Direction[direction]); 25928679Sbrian loglen += strlen(logbuf + loglen); 26026692Sbrian } 2616059Samurai ptop = (cp + (pip->ip_hl << 2)); 2626059Samurai 2636059Samurai switch (pip->ip_p) { 2646059Samurai case IPPROTO_ICMP: 26526692Sbrian if (logit && loglen < sizeof logbuf) { 26628679Sbrian icmph = (struct icmp *) ptop; 26728679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 26828679Sbrian "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 26928679Sbrian loglen += strlen(logbuf + loglen); 27028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 27128679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 27228679Sbrian loglen += strlen(logbuf + loglen); 2736059Samurai } 2746059Samurai break; 2756059Samurai case IPPROTO_UDP: 27626692Sbrian if (logit && loglen < sizeof logbuf) { 27728679Sbrian uh = (struct udphdr *) ptop; 27828679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 27928679Sbrian "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 28028679Sbrian loglen += strlen(logbuf + loglen); 28128679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 28228679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 28328679Sbrian loglen += strlen(logbuf + loglen); 2846059Samurai } 2856059Samurai break; 2866059Samurai case IPPROTO_TCP: 28728679Sbrian th = (struct tcphdr *) ptop; 2886059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 2896059Samurai pri = PRI_FAST; 29013733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 2916059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 29228679Sbrian pri = PRI_FAST; 2936059Samurai } 29426692Sbrian if (logit && loglen < sizeof logbuf) { 2956059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 29628679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 29728679Sbrian "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 29828679Sbrian loglen += strlen(logbuf + loglen); 29928679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 30028679Sbrian "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 30128679Sbrian loglen += strlen(logbuf + loglen); 3026059Samurai n = 0; 3036059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 30426692Sbrian if (th->th_flags & mask) { 30528679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 30628679Sbrian loglen += strlen(logbuf + loglen); 30728679Sbrian } 3086059Samurai n++; 3096059Samurai } 31028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 31128679Sbrian " seq:%x ack:%x (%d/%d)", 31228679Sbrian ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 31328679Sbrian loglen += strlen(logbuf + loglen); 3146059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 31528679Sbrian u_short *sp; 3166059Samurai 3176059Samurai ptop += 20; 31828679Sbrian sp = (u_short *) ptop; 31926692Sbrian if (ntohs(sp[0]) == 0x0204) { 32028679Sbrian snprintf(logbuf + loglen, sizeof logbuf - loglen, 32128679Sbrian " MSS = %d", ntohs(sp[1])); 32228679Sbrian loglen += strlen(logbuf + loglen); 32328679Sbrian } 3246059Samurai } 3256059Samurai } 3266059Samurai break; 3276059Samurai } 32826692Sbrian 32926692Sbrian if (logit) 33026692Sbrian LogPrintf(LogTCPIP, "%s\n", logbuf); 33128679Sbrian 33213733Sdfr if ((FilterCheck(pip, direction) & A_DENY)) { 33326516Sbrian LogPrintf(LogDEBUG, "blocked.\n"); 33428679Sbrian if (direction == 0) 33528679Sbrian IcmpError(pip, pri); 33628679Sbrian return (-1); 3376059Samurai } else { 33828679Sbrian if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 33928679Sbrian ipKeepAlive = FALSE; 3406735Samurai } else { 34128679Sbrian ipKeepAlive = TRUE; 3426735Samurai } 34328679Sbrian return (pri); 3446059Samurai } 3456059Samurai} 3466059Samurai 3476059Samuraivoid 34828679SbrianIpInput(struct mbuf * bp) 34928679Sbrian{ /* IN: Pointer to IP pakcet */ 3506059Samurai u_char *cp; 3516059Samurai struct mbuf *wp; 3526059Samurai int nb, nw; 3536059Samurai u_char tunbuff[MAX_MRU]; 3546059Samurai 3556059Samurai cp = tunbuff; 3566059Samurai nb = 0; 35728679Sbrian for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 3586059Samurai bcopy(MBUF_CTOP(wp), cp, wp->cnt); 3596059Samurai cp += wp->cnt; 3606059Samurai nb += wp->cnt; 3616059Samurai } 3626059Samurai 36320365Sjkh if (mode & MODE_ALIAS) { 36426031Sbrian int iresult; 36526031Sbrian char *fptr; 36626031Sbrian 36726142Sbrian iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff); 36826031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 36926031Sbrian 37026031Sbrian if (nb > MAX_MRU) { 37126516Sbrian LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 37226031Sbrian pfree(bp); 37326031Sbrian return; 37426031Sbrian } 37526031Sbrian if (iresult == PKT_ALIAS_OK 37628679Sbrian || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 37728679Sbrian if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 37828679Sbrian pfree(bp); 37928679Sbrian return; 38026031Sbrian } 38126031Sbrian ipInOctets += nb; 38226031Sbrian 38326031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 38426031Sbrian nw = write(tun_out, tunbuff, nb); 38526031Sbrian if (nw != nb) 38630092Sbrian if (nw == -1) 38730092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 38830092Sbrian strerror(errno)); 38930092Sbrian else 39030092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 39126031Sbrian 39226031Sbrian if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 39328679Sbrian while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) { 39428679Sbrian VarPacketAliasFragmentIn(tunbuff, fptr); 39528679Sbrian nb = ntohs(((struct ip *) fptr)->ip_len); 39628679Sbrian nw = write(tun_out, fptr, nb); 39728679Sbrian if (nw != nb) 39830092Sbrian if (nw == -1) 39930092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 40030092Sbrian strerror(errno)); 40130092Sbrian else 40230092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 40328679Sbrian free(fptr); 40428679Sbrian } 40526031Sbrian } 40628679Sbrian } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 40726031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 40826031Sbrian fptr = malloc(nb); 40926516Sbrian if (fptr == NULL) 41028679Sbrian LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 41126031Sbrian else { 41228679Sbrian memcpy(fptr, tunbuff, nb); 41328679Sbrian VarPacketAliasSaveFragment(fptr); 41426031Sbrian } 41526031Sbrian } 41628679Sbrian } else { /* no aliasing */ 41728679Sbrian if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 41826031Sbrian pfree(bp); 41926031Sbrian return; 42026031Sbrian } 42126031Sbrian ipInOctets += nb; 42226031Sbrian nw = write(tun_out, tunbuff, nb); 42326031Sbrian if (nw != nb) 42430092Sbrian if (nw == -1) 42530092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 42630092Sbrian else 42730092Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 4286059Samurai } 4296059Samurai pfree(bp); 4306059Samurai 4316059Samurai RestartIdleTimer(); 4326059Samurai} 4336059Samurai 43428679Sbrianstatic struct mqueue IpOutputQueues[PRI_FAST + 1]; 4356059Samurai 4366059Samuraivoid 43728679SbrianIpEnqueue(int pri, char *ptr, int count) 4386059Samurai{ 4396059Samurai struct mbuf *bp; 4406059Samurai 4416059Samurai bp = mballoc(count, MB_IPQ); 4426059Samurai bcopy(ptr, MBUF_CTOP(bp), count); 4436059Samurai Enqueue(&IpOutputQueues[pri], bp); 4446059Samurai} 4456059Samurai 4468857Srgrimesint 4477001SamuraiIsIpEnqueued() 4487001Samurai{ 4497001Samurai struct mqueue *queue; 45028679Sbrian int exist = FALSE; 45128679Sbrian 45213733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 45328679Sbrian if (queue->qlen > 0) { 45428679Sbrian exist = TRUE; 45528679Sbrian break; 45628679Sbrian } 4577001Samurai } 45828679Sbrian return (exist); 4597001Samurai} 4607001Samurai 4616059Samuraivoid 4626059SamuraiIpStartOutput() 4636059Samurai{ 4646059Samurai struct mqueue *queue; 4656059Samurai struct mbuf *bp; 46625630Sbrian int cnt; 4676059Samurai 4686059Samurai if (IpcpFsm.state != ST_OPENED) 4696059Samurai return; 47013733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 4716059Samurai if (queue->top) { 4726059Samurai bp = Dequeue(queue); 4736059Samurai if (bp) { 4746059Samurai cnt = plength(bp); 47513733Sdfr SendPppFrame(bp); 4766059Samurai RestartIdleTimer(); 4776059Samurai ipOutOctets += cnt; 47813733Sdfr break; 47928679Sbrian } 4806059Samurai } 4816059Samurai } 4826059Samurai} 483