ip.c revision 26516
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 * 2026516Sbrian * $Id: ip.c,v 1.20 1997/05/26 00:44:01 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 476059Samuraistatic void IdleTimeout() 486059Samurai{ 4926516Sbrian LogPrintf(LogPHASE, "Idle timer expired.\n"); 5026098Sbrian reconnect(RECON_FALSE); 516059Samurai LcpClose(); 526059Samurai} 536059Samurai 546059Samurai/* 556059Samurai * Start Idle timer. If timeout is reached, we call LcpClose() to 566059Samurai * close LCP and link. 576059Samurai */ 586059Samuraivoid 596059SamuraiStartIdleTimer() 606059Samurai{ 6120120Snate if (!(mode & (MODE_DEDICATED|MODE_DDIAL))) { 626059Samurai StopTimer(&IdleTimer); 636059Samurai IdleTimer.func = IdleTimeout; 646059Samurai IdleTimer.load = VarIdleTimeout * SECTICKS; 656059Samurai IdleTimer.state = TIMER_STOPPED; 666059Samurai StartTimer(&IdleTimer); 676059Samurai } 686059Samurai} 696059Samurai 706059Samuraivoid 7126516SbrianUpdateIdleTimer() 7226516Sbrian{ 7326516Sbrian if (IdleTimer.state == TIMER_RUNNING) 7426516Sbrian StartIdleTimer(); 7526516Sbrian} 7626516Sbrian 7726516Sbrianvoid 786059SamuraiStopIdleTimer() 796059Samurai{ 806059Samurai StopTimer(&IdleTimer); 816059Samurai} 826059Samurai 836059Samurai/* 846059Samurai * If any IP layer traffic is detected, refresh IdleTimer. 856059Samurai */ 866059Samuraistatic void 876059SamuraiRestartIdleTimer() 886059Samurai{ 8920120Snate if (!(mode & (MODE_DEDICATED|MODE_DDIAL)) && ipKeepAlive ) { 906059Samurai StartTimer(&IdleTimer); 916059Samurai ipIdleSecs = 0; 926059Samurai } 936059Samurai} 946059Samurai 9513733Sdfrstatic u_short interactive_ports[32] = { 9613733Sdfr 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9713733Sdfr 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 986059Samurai}; 996059Samurai 10013733Sdfr#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 1016059Samurai 1026059Samuraistatic char *TcpFlags[] = { 1036059Samurai "FIN", "SYN", "RST", "PSH", "ACK", "URG", 1046059Samurai}; 1056059Samurai 1066735Samuraistatic char *Direction[] = { "INP", "OUT", "OUT", "IN/OUT" }; 1076735Samuraistatic struct filterent *Filters[] = { ifilters, ofilters, dfilters, afilters }; 1086059Samurai 1096059Samuraistatic int 1106059SamuraiPortMatch(op, pport, rport) 1116059Samuraiint op; 1126059Samuraiu_short pport, rport; 1136059Samurai{ 1146059Samurai switch (op) { 1156059Samurai case OP_EQ: 1166059Samurai return(pport == rport); 1176059Samurai case OP_GT: 1186059Samurai return(pport > rport); 1196059Samurai case OP_LT: 1206059Samurai return(pport < rport); 1216059Samurai default: 1226059Samurai return(0); 1236059Samurai } 1246059Samurai} 1256059Samurai 1266059Samurai/* 1276059Samurai * Check a packet against with defined filters 1286059Samurai */ 1296059Samuraistatic int 1306059SamuraiFilterCheck(pip, direction) 1316059Samuraistruct ip *pip; 1326059Samuraiint direction; 1336059Samurai{ 1346059Samurai struct filterent *fp = Filters[direction]; 1356059Samurai int gotinfo, cproto, estab, n; 1366059Samurai struct tcphdr *th; 1376059Samurai struct udphdr *uh; 1386059Samurai struct icmp *ih; 1396059Samurai char *ptop; 1406059Samurai u_short sport, dport; 1416059Samurai 1426059Samurai if (fp->action) { 1436059Samurai cproto = gotinfo = estab = 0; 1446059Samurai sport = dport = 0; 1456059Samurai for (n = 0; n < MAXFILTERS; n++) { 1466059Samurai if (fp->action) { 14710858Samurai /* permit fragments on in and out filter */ 14810858Samurai if ((direction == FL_IN || direction == FL_OUT) && 14913733Sdfr (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 15010858Samurai return(A_PERMIT); 15110858Samurai } 15226516Sbrian LogPrintf(LogDEBUG, "rule = %d\n", n); 1536059Samurai if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr 1546059Samurai && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) { 1556059Samurai if (fp->proto) { 1566059Samurai if (!gotinfo) { 1576059Samurai ptop = (char *)pip + (pip->ip_hl << 2); 1586059Samurai 1596059Samurai switch (pip->ip_p) { 1606059Samurai case IPPROTO_ICMP: 1616059Samurai cproto = P_ICMP; ih = (struct icmp *)ptop; 1626059Samurai sport = ih->icmp_type; estab = 1; 1636059Samurai break; 1646059Samurai case IPPROTO_UDP: 1656059Samurai cproto = P_UDP; uh = (struct udphdr *)ptop; 1666059Samurai sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport); 1676059Samurai estab = 1; 1686059Samurai break; 1696059Samurai case IPPROTO_TCP: 1706059Samurai cproto = P_TCP; th = (struct tcphdr *)ptop; 1716059Samurai sport = ntohs(th->th_sport); dport = ntohs(th->th_dport); 1726059Samurai estab = (th->th_flags & TH_ACK); 17326516Sbrian if (estab == 0) 17426516Sbrian LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 17526516Sbrian th->th_flags, sport, dport); 1766059Samurai break; 1776059Samurai default: 1786059Samurai return(A_DENY); /* We'll block unknown type of packet */ 1796059Samurai } 1806059Samurai gotinfo = 1; 18126516Sbrian LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 18226516Sbrian " dstop = %d, estab = %d\n", direction, cproto, 18326516Sbrian fp->opt.srcop, fp->opt.dstop, estab); 1846059Samurai } 18526516Sbrian 18626516Sbrian LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 18726516Sbrian " dport = %d\n", n, cproto, sport, dport); 18826516Sbrian LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 18926516Sbrian 1906059Samurai if (cproto == fp->proto) { 1916059Samurai if ((fp->opt.srcop == OP_NONE || 1926059Samurai PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 1936059Samurai && 1946059Samurai (fp->opt.dstop == OP_NONE || 1956059Samurai PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 1966059Samurai && 1976059Samurai (fp->opt.estab == 0 || estab)) { 1986059Samurai return(fp->action); 1996059Samurai } 2006059Samurai } 2016059Samurai } else { 2026059Samurai /* Address is mached. Make a decision. */ 20326516Sbrian LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 2046059Samurai return(fp->action); 2056059Samurai } 2066059Samurai } 2076059Samurai } 2086059Samurai fp++; 2096059Samurai } 2106059Samurai return(A_DENY); /* No rule is mached. Deny this packet */ 2116059Samurai } 2126059Samurai return(A_PERMIT); /* No rule is given. Permit this packet */ 2136059Samurai} 2146059Samurai 2156059Samuraistatic void 2166059SamuraiIcmpError(pip, code) 2176059Samuraistruct ip *pip; 2186059Samuraiint 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 2376059SamuraiPacketCheck(cp, nb, direction) 2386059Samuraichar *cp; 2396059Samuraiint nb; 2406059Samuraiint direction; 2416059Samurai{ 2426059Samurai struct ip *pip; 2436059Samurai struct tcphdr *th; 2446059Samurai struct udphdr *uh; 2456059Samurai struct icmp *icmph; 2466059Samurai char *ptop; 2476059Samurai int mask, len, n; 2486059Samurai int logit; 2496059Samurai int pri = PRI_NORMAL; 2506059Samurai 25126516Sbrian logit = LogIsKept(LogTCPIP); 2526059Samurai 2536059Samurai pip = (struct ip *)cp; 2548857Srgrimes 25526516Sbrian if (logit) LogPrintf(LogTCPIP, "%s ", Direction[direction]); 2566059Samurai 2576059Samurai ptop = (cp + (pip->ip_hl << 2)); 2586059Samurai 2596059Samurai switch (pip->ip_p) { 2606059Samurai case IPPROTO_ICMP: 2616059Samurai if (logit) { 2626059Samurai icmph = (struct icmp *)ptop; 26326516Sbrian LogPrintf(LogTCPIP, "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 26426516Sbrian LogPrintf(LogTCPIP, "%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type); 2656059Samurai } 2666059Samurai break; 2676059Samurai case IPPROTO_UDP: 2686059Samurai if (logit) { 2696059Samurai uh = (struct udphdr *)ptop; 27026516Sbrian LogPrintf(LogTCPIP, "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 27126516Sbrian LogPrintf(LogTCPIP, "%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 2726059Samurai } 2736059Samurai break; 2746059Samurai case IPPROTO_TCP: 2756059Samurai th = (struct tcphdr *)ptop; 2766059Samurai if (pip->ip_tos == IPTOS_LOWDELAY) 2776059Samurai pri = PRI_FAST; 27813733Sdfr else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 2796059Samurai if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 2806059Samurai pri = PRI_FAST; 2816059Samurai } 2826059Samurai 2836059Samurai if (logit) { 2846059Samurai len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 28526516Sbrian LogPrintf(LogTCPIP, "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 28626516Sbrian LogPrintf(LogTCPIP, "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 2876059Samurai n = 0; 2886059Samurai for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 2896059Samurai if (th->th_flags & mask) 29026516Sbrian LogPrintf(LogTCPIP, " %s", TcpFlags[n]); 2916059Samurai n++; 2926059Samurai } 29326516Sbrian LogPrintf(LogTCPIP, " seq:%x ack:%x (%d/%d)\n", 2946059Samurai ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 2956059Samurai if ((th->th_flags & TH_SYN) && nb > 40) { 2966059Samurai u_short *sp; 2976059Samurai 2986059Samurai ptop += 20; 2996059Samurai sp = (u_short *)ptop; 3006059Samurai if (ntohs(sp[0]) == 0x0204) 30126516Sbrian LogPrintf(LogTCPIP, " MSS = %d\n", ntohs(sp[1])); 3026059Samurai } 3036059Samurai } 3046059Samurai break; 3056059Samurai } 30613733Sdfr 30713733Sdfr if ((FilterCheck(pip, direction) & A_DENY)) { 30826516Sbrian LogPrintf(LogDEBUG, "blocked.\n"); 3096059Samurai if (direction == 0) IcmpError(pip, pri); 3106059Samurai return(-1); 3116059Samurai } else { 3127001Samurai if ( FilterCheck(pip, FL_KEEP ) & A_DENY ) { /* Check Keep Alive filter */ 3136735Samurai ipKeepAlive = FALSE; 3146735Samurai } else { 3156735Samurai ipKeepAlive = TRUE; 3166735Samurai } 3176059Samurai return(pri); 3186059Samurai } 3196059Samurai} 3206059Samurai 3216059Samuraivoid 3226059SamuraiIpInput(bp) 3236059Samuraistruct mbuf *bp; /* IN: Pointer to IP pakcet */ 3246059Samurai{ 3256059Samurai u_char *cp; 3266059Samurai struct mbuf *wp; 3276059Samurai int nb, nw; 3286059Samurai u_char tunbuff[MAX_MRU]; 3296059Samurai 3306059Samurai cp = tunbuff; 3316059Samurai nb = 0; 33226516Sbrian for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 3336059Samurai bcopy(MBUF_CTOP(wp), cp, wp->cnt); 3346059Samurai cp += wp->cnt; 3356059Samurai nb += wp->cnt; 3366059Samurai } 3376059Samurai 33820365Sjkh if (mode & MODE_ALIAS) { 33926031Sbrian int iresult; 34026031Sbrian char *fptr; 34126031Sbrian 34226142Sbrian iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff); 34326031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 34426031Sbrian 34526031Sbrian if (nb > MAX_MRU) { 34626516Sbrian LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 34726031Sbrian pfree(bp); 34826031Sbrian return; 34926031Sbrian } 35026031Sbrian 35126031Sbrian if (iresult == PKT_ALIAS_OK 35226031Sbrian || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 35326031Sbrian if ( PacketCheck(tunbuff, nb, FL_IN ) < 0) { 35426031Sbrian pfree(bp); 35526031Sbrian return; 35626031Sbrian } 35726031Sbrian 35826031Sbrian ipInOctets += nb; 35926031Sbrian 36026031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 36126031Sbrian nw = write(tun_out, tunbuff, nb); 36226031Sbrian if (nw != nb) 36326516Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 36426031Sbrian 36526031Sbrian if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 36626142Sbrian while ((fptr = VarGetNextFragmentPtr(tunbuff)) != NULL) { 36726142Sbrian VarFragmentAliasIn(tunbuff, fptr); 36826031Sbrian nb = ntohs(((struct ip *) fptr)->ip_len); 36926031Sbrian nw = write(tun_out, fptr, nb); 37026031Sbrian if (nw != nb) 37126516Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 37226031Sbrian free(fptr); 37326031Sbrian } 37426031Sbrian } 37526031Sbrian } 37626031Sbrian else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 37726031Sbrian nb = ntohs(((struct ip *) tunbuff)->ip_len); 37826031Sbrian fptr = malloc(nb); 37926516Sbrian if (fptr == NULL) 38026516Sbrian LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 38126031Sbrian else { 38226031Sbrian memcpy(fptr, tunbuff, nb); 38326142Sbrian VarSaveFragmentPtr(fptr); 38426031Sbrian } 38526031Sbrian } 38620365Sjkh } 38726031Sbrian else 38826031Sbrian { /* no aliasing */ 38926031Sbrian if ( PacketCheck(tunbuff, nb, FL_IN ) < 0) 39026031Sbrian { 39126031Sbrian pfree(bp); 39226031Sbrian return; 39326031Sbrian } 39420365Sjkh 39526031Sbrian ipInOctets += nb; 39626031Sbrian nw = write(tun_out, tunbuff, nb); 39726031Sbrian if (nw != nb) 39826516Sbrian LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 3996059Samurai } 4006059Samurai pfree(bp); 4016059Samurai 4026059Samurai RestartIdleTimer(); 4036059Samurai} 4046059Samurai 40513733Sdfrstatic struct mqueue IpOutputQueues[PRI_FAST+1]; 4066059Samurai 4076059Samuraivoid 4086059SamuraiIpEnqueue(pri, ptr, count) 4096059Samuraiint pri; 4106059Samuraichar *ptr; 4116059Samuraiint count; 4126059Samurai{ 4136059Samurai struct mbuf *bp; 4146059Samurai 4156059Samurai bp = mballoc(count, MB_IPQ); 4166059Samurai bcopy(ptr, MBUF_CTOP(bp), count); 4176059Samurai Enqueue(&IpOutputQueues[pri], bp); 4186059Samurai} 4196059Samurai 4208857Srgrimesint 4217001SamuraiIsIpEnqueued() 4227001Samurai{ 4237001Samurai struct mqueue *queue; 4247001Samurai int exist = FALSE; 42513733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 4267001Samurai if ( queue->qlen > 0 ) { 4277001Samurai exist = TRUE; 4287001Samurai break; 4297001Samurai } 4307001Samurai } 4317001Samurai return( exist ); 4327001Samurai} 4337001Samurai 4346059Samuraivoid 4356059SamuraiIpStartOutput() 4366059Samurai{ 4376059Samurai struct mqueue *queue; 4386059Samurai struct mbuf *bp; 43925630Sbrian int cnt; 4406059Samurai 4416059Samurai if (IpcpFsm.state != ST_OPENED) 4426059Samurai return; 44313733Sdfr for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 4446059Samurai if (queue->top) { 4456059Samurai bp = Dequeue(queue); 4466059Samurai if (bp) { 4476059Samurai cnt = plength(bp); 44813733Sdfr SendPppFrame(bp); 4496059Samurai RestartIdleTimer(); 4506059Samurai ipOutOctets += cnt; 45113733Sdfr break; 4526059Samurai } 4536059Samurai } 4546059Samurai } 4556059Samurai} 456