ip.c revision 6059
1120304Swpaul/* 2119898Swpaul * PPP IP Protocol Interface 3119898Swpaul * 4119898Swpaul * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5119898Swpaul * 6119898Swpaul * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7119898Swpaul * 8119898Swpaul * Redistribution and use in source and binary forms are permitted 9119898Swpaul * provided that the above copyright notice and this paragraph are 10119898Swpaul * duplicated in all such forms and that any documentation, 11119898Swpaul * advertising materials, and other materials related to such 12119898Swpaul * distribution and use acknowledge that the software was developed 13119898Swpaul * by the Internet Initiative Japan. The name of the 14119898Swpaul * IIJ may not be used to endorse or promote products derived 15119898Swpaul * from this software without specific prior written permission. 16119898Swpaul * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17119898Swpaul * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18119898Swpaul * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19119898Swpaul * 20119898Swpaul * $Id:$ 21119898Swpaul * 22119898Swpaul * TODO: 23119898Swpaul * o Return ICMP message for filterd packet 24119898Swpaul * and optionaly record it into log. 25119898Swpaul */ 26119898Swpaul#include "fsm.h" 27119898Swpaul#include "lcpproto.h" 28119898Swpaul#include "hdlc.h" 29119898Swpaul#include <netinet/in_systm.h> 30119898Swpaul#include <netinet/ip.h> 31119898Swpaul#include <netinet/ip_icmp.h> 32119898Swpaul#include <netinet/udp.h> 33217914Syongari#include <netinet/tcp.h> 34119898Swpaul#include "vars.h" 35119898Swpaul#include "filter.h" 36119898Swpaul 37119898Swpaulextern void SendPppFlame(); 38214432Syongariextern int PacketCheck(); 39119898Swpaulextern void LcpClose(); 40151046Strhodes 41151046Strhodesstatic struct pppTimer IdleTimer; 42148220Strhodes 43148145Strhodesstatic void IdleTimeout() 44119898Swpaul{ 45119898Swpaul LogPrintf(LOG_PHASE, "Idle timer expired.\n"); 46148145Strhodes LcpClose(); 47148145Strhodes} 48151046Strhodes 49151046Strhodes/* 50148145Strhodes * Start Idle timer. If timeout is reached, we call LcpClose() to 51148145Strhodes * close LCP and link. 52148145Strhodes */ 53148145Strhodesvoid 54119898SwpaulStartIdleTimer() 55119898Swpaul{ 56119898Swpaul if (!(mode & MODE_DEDICATED)) { 57119898Swpaul StopTimer(&IdleTimer); 58214432Syongari IdleTimer.func = IdleTimeout; 59159962Swpaul IdleTimer.load = VarIdleTimeout * SECTICKS; 60119898Swpaul IdleTimer.state = TIMER_STOPPED; 61214432Syongari StartTimer(&IdleTimer); 62159962Swpaul } 63214432Syongari} 64214432Syongari 65119898Swpaulvoid 66119898SwpaulStopIdleTimer() 67119898Swpaul{ 68119898Swpaul StopTimer(&IdleTimer); 69131530Sru} 70131530Sru 71119898Swpaul/* 72119898Swpaul * If any IP layer traffic is detected, refresh IdleTimer. 73119898Swpaul */ 74119898Swpaulstatic void 75214432SyongariRestartIdleTimer() 76214432Syongari{ 77131530Sru if (!(mode & MODE_DEDICATED)) { 78131530Sru StopTimer(&IdleTimer); 79131530Sru StartTimer(&IdleTimer); 80119898Swpaul ipIdleSecs = 0; 81119898Swpaul } 82119898Swpaul} 83119898Swpaul 84135899Sjmgstatic u_short interactive_ports[8] = { 85119898Swpaul 0, 513, 0, 0, 0, 21, 0, 23, 86119898Swpaul}; 87119898Swpaul 88119898Swpaul#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p)) 89119898Swpaul 90119898Swpaulstatic char *TcpFlags[] = { 91119898Swpaul "FIN", "SYN", "RST", "PSH", "ACK", "URG", 92131801Sru}; 93119898Swpaul 94119898Swpaulstatic char *Direction[] = { "INP", "OUT", "OUT" }; 95119898Swpaulstatic struct filterent *Filters[] = { ifilters, ofilters, dfilters }; 96119898Swpaul 97119898Swpaulstatic int 98119898SwpaulPortMatch(op, pport, rport) 99119898Swpaulint op; 100119898Swpaulu_short pport, rport; 101119898Swpaul{ 102131801Sru switch (op) { 103119898Swpaul case OP_EQ: 104119898Swpaul return(pport == rport); 105119898Swpaul case OP_GT: 106119898Swpaul return(pport > rport); 107119898Swpaul case OP_LT: 108119898Swpaul return(pport < rport); 109131801Sru default: 110119898Swpaul return(0); 111119898Swpaul } 112131801Sru} 113119898Swpaul 114119898Swpaul/* 115119898Swpaul * Check a packet against with defined filters 116119898Swpaul */ 117119898Swpaulstatic int 118119898SwpaulFilterCheck(pip, direction) 119119898Swpaulstruct ip *pip; 120119898Swpaulint direction; 121119898Swpaul{ 122119898Swpaul struct filterent *fp = Filters[direction]; 123119898Swpaul int gotinfo, cproto, estab, n; 124131801Sru struct tcphdr *th; 125119898Swpaul struct udphdr *uh; 126119898Swpaul struct icmp *ih; 127119898Swpaul char *ptop; 128119898Swpaul u_short sport, dport; 129119898Swpaul 130119898Swpaul if (fp->action) { 131119898Swpaul cproto = gotinfo = estab = 0; 132119898Swpaul sport = dport = 0; 133119898Swpaul for (n = 0; n < MAXFILTERS; n++) { 134119898Swpaul if (fp->action) { 135131801Sru#ifdef DEBUG 136119898Swpaullogprintf("rule = %d\n", n); 137119898Swpaul#endif 138119898Swpaul if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr 139119898Swpaul && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) { 140119898Swpaul if (fp->proto) { 141119898Swpaul if (!gotinfo) { 142119898Swpaul ptop = (char *)pip + (pip->ip_hl << 2); 143119898Swpaul 144134778Sbrueffer switch (pip->ip_p) { 145134778Sbrueffer case IPPROTO_ICMP: 146134778Sbrueffer cproto = P_ICMP; ih = (struct icmp *)ptop; 147214432Syongari sport = ih->icmp_type; estab = 1; 148214432Syongari break; 149134778Sbrueffer case IPPROTO_UDP: 150134778Sbrueffer cproto = P_UDP; uh = (struct udphdr *)ptop; 151134778Sbrueffer sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport); 152134778Sbrueffer estab = 1; 153134778Sbrueffer break; 154134778Sbrueffer case IPPROTO_TCP: 155134778Sbrueffer cproto = P_TCP; th = (struct tcphdr *)ptop; 156134778Sbrueffer sport = ntohs(th->th_sport); dport = ntohs(th->th_dport); 157134778Sbrueffer estab = (th->th_flags & TH_ACK); 158148732Stobez break; 159148732Stobez default: 160134778Sbrueffer return(A_DENY); /* We'll block unknown type of packet */ 161134778Sbrueffer } 162137828Sbrueffer gotinfo = 1; 163137828Sbrueffer#ifdef DEBUG 164154362Sbzlogprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n", 165154362Sbzdirection, cproto, fp->opt.srcop, fp->opt.dstop, estab); 166134778Sbruefferif (estab == 0) 167134778Sbruefferlogprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport); 168164532Syongari#endif 169164532Syongari } 170134778Sbrueffer#ifdef DEBUG 171134778Sbrueffer logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n", 172188382Syongari n, cproto, sport, dport); 173188382Syongari logprintf("check0: action = %d\n", fp->action); 174188382Syongari#endif 175188382Syongari if (cproto == fp->proto) { 176188382Syongari if ((fp->opt.srcop == OP_NONE || 177188382Syongari PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 178217914Syongari && 179217914Syongari (fp->opt.dstop == OP_NONE || 180217914Syongari PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 181217914Syongari && 182217914Syongari (fp->opt.estab == 0 || estab)) { 183217914Syongari return(fp->action); 184188382Syongari } 185188382Syongari } 186188382Syongari } else { 187217914Syongari /* Address is mached. Make a decision. */ 188217914Syongari#ifdef DEBUG 189217914Syongari logprintf("check1: action = %d\n", fp->action); 190216131Syongari#endif 191216131Syongari return(fp->action); 192216131Syongari } 193216131Syongari } 194216131Syongari } 195188382Syongari fp++; 196217914Syongari } 197217914Syongaridrop: 198217914Syongari return(A_DENY); /* No rule is mached. Deny this packet */ 199217914Syongari } 200217914Syongari return(A_PERMIT); /* No rule is given. Permit this packet */ 201217914Syongari} 202217914Syongari 203217914Syongaristatic void 204217914SyongariIcmpError(pip, code) 205217914Syongaristruct ip *pip; 206217914Syongariint code; 207217914Syongari{ 208217914Syongari#ifdef notdef 209217914Syongari struct mbuf *bp; 210217914Syongari 211119898Swpaul if (pip->ip_p != IPPROTO_ICMP) { 212119898Swpaul bp = mballoc(cnt, MB_IPIN); 213119898Swpaul bcopy(ptr, MBUF_CTOP(bp), cnt); 214119898Swpaul SendPppFlame(PRI_URGENT, bp); 215119898Swpaul RestartIdleTimer(); 216119898Swpaul ipOutOctets += cnt; 217119898Swpaul } 218119898Swpaul#endif 219119898Swpaul} 220119898Swpaul 221119898Swpaul/* 222119898Swpaul * For debugging aid. 223119898Swpaul */ 224119898Swpaulint 225119898SwpaulPacketCheck(cp, nb, direction) 226119898Swpaulchar *cp; 227119898Swpaulint nb; 228119898Swpaulint direction; 229119898Swpaul{ 230119898Swpaul struct ip *pip; 231119898Swpaul struct tcphdr *th; 232119898Swpaul struct udphdr *uh; 233119898Swpaul struct icmp *icmph; 234166346Sbrueffer char *ptop; 235119898Swpaul int mask, len, n; 236124302Sbrueffer int logit; 237119898Swpaul int pri = PRI_NORMAL; 238119898Swpaul 239138068Sbrueffer logit = (loglevel & (1 << LOG_TCPIP)); 240217464Smarius 241119898Swpaul pip = (struct ip *)cp; 242119898Swpaul 243119898Swpaul if (logit) logprintf("%s ", Direction[direction]); 244119898Swpaul 245202386Sru ptop = (cp + (pip->ip_hl << 2)); 246119898Swpaul 247119898Swpaul switch (pip->ip_p) { 248119898Swpaul case IPPROTO_ICMP: 249119898Swpaul if (logit) { 250119898Swpaul icmph = (struct icmp *)ptop; 251119898Swpaul logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 252119898Swpaul logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type); 253119898Swpaul } 254119898Swpaul break; 255119898Swpaul case IPPROTO_UDP: 256119898Swpaul if (logit) { 257119898Swpaul uh = (struct udphdr *)ptop; 258119898Swpaul logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 259119898Swpaul logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 260131530Sru } 261131530Sru break; 262119898Swpaul case IPPROTO_TCP: 263131530Sru th = (struct tcphdr *)ptop; 264131530Sru if (pip->ip_tos == IPTOS_LOWDELAY) 265119898Swpaul pri = PRI_FAST; 266119898Swpaul else if (pip->ip_off == 0) { 267119898Swpaul if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 268119898Swpaul pri = PRI_FAST; 269131530Sru } 270131530Sru 271119898Swpaul if (logit) { 272119898Swpaul len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 273119898Swpaul logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 274131530Sru logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 275131530Sru n = 0; 276119898Swpaul for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 277131530Sru if (th->th_flags & mask) 278131530Sru logprintf(" %s", TcpFlags[n]); 279131530Sru n++; 280131530Sru } 281211936Sbrucec logprintf(" seq:%x ack:%x (%d/%d)\n", 282119898Swpaul ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 283119898Swpaul if ((th->th_flags & TH_SYN) && nb > 40) { 284119898Swpaul u_short *sp; 285119898Swpaul 286 ptop += 20; 287 sp = (u_short *)ptop; 288 if (ntohs(sp[0]) == 0x0204) 289 logprintf(" MSS = %d\n", ntohs(sp[1])); 290 } 291 } 292 break; 293 } 294 pri = FilterCheck(pip, direction); 295 if (pri & A_DENY) { 296#ifdef DEBUG 297 logprintf("blocked.\n"); 298#endif 299 if (direction == 0) IcmpError(pip, pri); 300 return(-1); 301 } else { 302 return(pri); 303 } 304} 305 306void 307IpInput(bp) 308struct mbuf *bp; /* IN: Pointer to IP pakcet */ 309{ 310 u_char *cp; 311 struct mbuf *wp; 312 int nb, nw; 313 u_char tunbuff[MAX_MRU]; 314 315 cp = tunbuff; 316 nb = 0; 317 for (wp = bp; wp; wp = wp->next) { /* Copy to continuois region */ 318 bcopy(MBUF_CTOP(wp), cp, wp->cnt); 319 cp += wp->cnt; 320 nb += wp->cnt; 321 } 322 323 if (PacketCheck(tunbuff, nb, 0) < 0) { 324 pfree(bp); 325 return; 326 } 327 328 ipInOctets += nb; 329 /* 330 * Pass it to tunnel device 331 */ 332 nw = write(tun_out, tunbuff, nb); 333 if (nw != nb) 334 fprintf(stderr, "wrote %d, got %d\r\n"); 335 pfree(bp); 336 337 RestartIdleTimer(); 338} 339 340void 341IpOutput(ptr, cnt) 342u_char *ptr; /* IN: Pointer to IP packet */ 343int cnt; /* IN: Length of packet */ 344{ 345 struct mbuf *bp; 346 int pri; 347 348 if (IpcpFsm.state != ST_OPENED) 349 return; 350 351 pri = PacketCheck(ptr, cnt, 1); 352 if (pri >= 0) { 353 bp = mballoc(cnt, MB_IPIN); 354 bcopy(ptr, MBUF_CTOP(bp), cnt); 355 SendPppFlame(pri, bp); 356 RestartIdleTimer(); 357 ipOutOctets += cnt; 358 } 359} 360 361static struct mqueue IpOutputQueues[PRI_URGENT+1]; 362 363void 364IpEnqueue(pri, ptr, count) 365int pri; 366char *ptr; 367int count; 368{ 369 struct mbuf *bp; 370 371 bp = mballoc(count, MB_IPQ); 372 bcopy(ptr, MBUF_CTOP(bp), count); 373 Enqueue(&IpOutputQueues[pri], bp); 374} 375 376void 377IpStartOutput() 378{ 379 struct mqueue *queue; 380 struct mbuf *bp; 381 int pri, cnt; 382 383 if (IpcpFsm.state != ST_OPENED) 384 return; 385 pri = PRI_URGENT; 386 for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) { 387 if (queue->top) { 388 bp = Dequeue(queue); 389 if (bp) { 390 cnt = plength(bp); 391 SendPppFlame(pri, bp); 392 RestartIdleTimer(); 393 ipOutOctets += cnt; 394 } 395 } 396 pri--; 397 } 398} 399