ip.c revision 30715
1/* 2 * PPP IP Protocol Interface 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: ip.c,v 1.25 1997/10/04 00:14:39 brian Exp $ 21 * 22 * TODO: 23 * o Return ICMP message for filterd packet 24 * and optionaly record it into log. 25 */ 26#include <sys/param.h> 27#include <netinet/in.h> 28#include <netinet/in_systm.h> 29#include <netinet/ip.h> 30#include <netinet/ip_icmp.h> 31#include <netinet/udp.h> 32#include <netinet/tcp.h> 33#include <arpa/inet.h> 34 35#include <alias.h> 36#include <errno.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <unistd.h> 41 42#include "mbuf.h" 43#include "log.h" 44#include "defs.h" 45#include "timer.h" 46#include "fsm.h" 47#include "lcpproto.h" 48#include "hdlc.h" 49#include "loadalias.h" 50#include "command.h" 51#include "vars.h" 52#include "filter.h" 53#include "log.h" 54#include "os.h" 55#include "ipcp.h" 56#include "vjcomp.h" 57#include "lcp.h" 58#include "ip.h" 59 60static struct pppTimer IdleTimer; 61 62static void 63IdleTimeout() 64{ 65 LogPrintf(LogPHASE, "Idle timer expired.\n"); 66 reconnect(RECON_FALSE); 67 LcpClose(); 68} 69 70/* 71 * Start Idle timer. If timeout is reached, we call LcpClose() to 72 * close LCP and link. 73 */ 74void 75StartIdleTimer() 76{ 77 if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 78 StopTimer(&IdleTimer); 79 IdleTimer.func = IdleTimeout; 80 IdleTimer.load = VarIdleTimeout * SECTICKS; 81 IdleTimer.state = TIMER_STOPPED; 82 StartTimer(&IdleTimer); 83 } 84} 85 86void 87UpdateIdleTimer() 88{ 89 if (OsLinkIsUp()) 90 StartIdleTimer(); 91} 92 93void 94StopIdleTimer() 95{ 96 StopTimer(&IdleTimer); 97} 98 99/* 100 * If any IP layer traffic is detected, refresh IdleTimer. 101 */ 102static void 103RestartIdleTimer() 104{ 105 if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 106 StartTimer(&IdleTimer); 107 ipIdleSecs = 0; 108 } 109} 110 111static u_short interactive_ports[32] = { 112 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 114}; 115 116#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 117 118static char *TcpFlags[] = { 119 "FIN", "SYN", "RST", "PSH", "ACK", "URG", 120}; 121 122static char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 123static struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 124 125static int 126PortMatch(int op, u_short pport, u_short rport) 127{ 128 switch (op) { 129 case OP_EQ: 130 return (pport == rport); 131 case OP_GT: 132 return (pport > rport); 133 case OP_LT: 134 return (pport < rport); 135 default: 136 return (0); 137 } 138} 139 140/* 141 * Check a packet against with defined filters 142 */ 143static int 144FilterCheck(struct ip * pip, int direction) 145{ 146 struct filterent *fp = Filters[direction]; 147 int gotinfo, cproto, estab, n; 148 struct tcphdr *th; 149 struct udphdr *uh; 150 struct icmp *ih; 151 char *ptop; 152 u_short sport, dport; 153 154 if (fp->action) { 155 cproto = gotinfo = estab = 0; 156 sport = dport = 0; 157 for (n = 0; n < MAXFILTERS; n++) { 158 if (fp->action) { 159 /* permit fragments on in and out filter */ 160 if ((direction == FL_IN || direction == FL_OUT) && 161 (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 162 return (A_PERMIT); 163 } 164 LogPrintf(LogDEBUG, "rule = %d\n", n); 165 if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr 166 && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) { 167 if (fp->proto) { 168 if (!gotinfo) { 169 ptop = (char *) pip + (pip->ip_hl << 2); 170 171 switch (pip->ip_p) { 172 case IPPROTO_ICMP: 173 cproto = P_ICMP; 174 ih = (struct icmp *) ptop; 175 sport = ih->icmp_type; 176 estab = 1; 177 break; 178 case IPPROTO_UDP: 179 cproto = P_UDP; 180 uh = (struct udphdr *) ptop; 181 sport = ntohs(uh->uh_sport); 182 dport = ntohs(uh->uh_dport); 183 estab = 1; 184 break; 185 case IPPROTO_TCP: 186 cproto = P_TCP; 187 th = (struct tcphdr *) ptop; 188 sport = ntohs(th->th_sport); 189 dport = ntohs(th->th_dport); 190 estab = (th->th_flags & TH_ACK); 191 if (estab == 0) 192 LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 193 th->th_flags, sport, dport); 194 break; 195 default: 196 return (A_DENY);/* We'll block unknown type of packet */ 197 } 198 gotinfo = 1; 199 LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 200 " dstop = %d, estab = %d\n", direction, cproto, 201 fp->opt.srcop, fp->opt.dstop, estab); 202 } 203 LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 204 " dport = %d\n", n, cproto, sport, dport); 205 LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 206 207 if (cproto == fp->proto) { 208 if ((fp->opt.srcop == OP_NONE || 209 PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 210 && 211 (fp->opt.dstop == OP_NONE || 212 PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 213 && 214 (fp->opt.estab == 0 || estab)) { 215 return (fp->action); 216 } 217 } 218 } else { 219 /* Address is mached. Make a decision. */ 220 LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 221 return (fp->action); 222 } 223 } 224 } 225 fp++; 226 } 227 return (A_DENY); /* No rule is mached. Deny this packet */ 228 } 229 return (A_PERMIT); /* No rule is given. Permit this packet */ 230} 231 232static void 233IcmpError(struct ip * pip, int code) 234{ 235#ifdef notdef 236 struct mbuf *bp; 237 238 if (pip->ip_p != IPPROTO_ICMP) { 239 bp = mballoc(cnt, MB_IPIN); 240 memcpy(MBUF_CTOP(bp), ptr, cnt); 241 SendPppFrame(bp); 242 RestartIdleTimer(); 243 ipOutOctets += cnt; 244 } 245#endif 246} 247 248/* 249 * For debugging aid. 250 */ 251int 252PacketCheck(char *cp, int nb, int direction) 253{ 254 struct ip *pip; 255 struct tcphdr *th; 256 struct udphdr *uh; 257 struct icmp *icmph; 258 char *ptop; 259 int mask, len, n; 260 int pri = PRI_NORMAL; 261 int logit, loglen; 262 static char logbuf[200]; 263 264 logit = LogIsKept(LogTCPIP); 265 loglen = 0; 266 267 pip = (struct ip *) cp; 268 269 if (logit && loglen < sizeof logbuf) { 270 snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 271 Direction[direction]); 272 loglen += strlen(logbuf + loglen); 273 } 274 ptop = (cp + (pip->ip_hl << 2)); 275 276 switch (pip->ip_p) { 277 case IPPROTO_ICMP: 278 if (logit && loglen < sizeof logbuf) { 279 icmph = (struct icmp *) ptop; 280 snprintf(logbuf + loglen, sizeof logbuf - loglen, 281 "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 282 loglen += strlen(logbuf + loglen); 283 snprintf(logbuf + loglen, sizeof logbuf - loglen, 284 "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 285 loglen += strlen(logbuf + loglen); 286 } 287 break; 288 case IPPROTO_UDP: 289 if (logit && loglen < sizeof logbuf) { 290 uh = (struct udphdr *) ptop; 291 snprintf(logbuf + loglen, sizeof logbuf - loglen, 292 "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 293 loglen += strlen(logbuf + loglen); 294 snprintf(logbuf + loglen, sizeof logbuf - loglen, 295 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 296 loglen += strlen(logbuf + loglen); 297 } 298 break; 299 case IPPROTO_TCP: 300 th = (struct tcphdr *) ptop; 301 if (pip->ip_tos == IPTOS_LOWDELAY) 302 pri = PRI_FAST; 303 else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 304 if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 305 pri = PRI_FAST; 306 } 307 if (logit && loglen < sizeof logbuf) { 308 len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 309 snprintf(logbuf + loglen, sizeof logbuf - loglen, 310 "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 311 loglen += strlen(logbuf + loglen); 312 snprintf(logbuf + loglen, sizeof logbuf - loglen, 313 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 314 loglen += strlen(logbuf + loglen); 315 n = 0; 316 for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 317 if (th->th_flags & mask) { 318 snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 319 loglen += strlen(logbuf + loglen); 320 } 321 n++; 322 } 323 snprintf(logbuf + loglen, sizeof logbuf - loglen, 324 " seq:%x ack:%x (%d/%d)", 325 ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 326 loglen += strlen(logbuf + loglen); 327 if ((th->th_flags & TH_SYN) && nb > 40) { 328 u_short *sp; 329 330 ptop += 20; 331 sp = (u_short *) ptop; 332 if (ntohs(sp[0]) == 0x0204) { 333 snprintf(logbuf + loglen, sizeof logbuf - loglen, 334 " MSS = %d", ntohs(sp[1])); 335 loglen += strlen(logbuf + loglen); 336 } 337 } 338 } 339 break; 340 } 341 342 if (logit) 343 LogPrintf(LogTCPIP, "%s\n", logbuf); 344 345 if ((FilterCheck(pip, direction) & A_DENY)) { 346 LogPrintf(LogDEBUG, "blocked.\n"); 347 if (direction == 0) 348 IcmpError(pip, pri); 349 return (-1); 350 } else { 351 if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 352 ipKeepAlive = 0; 353 } else { 354 ipKeepAlive = 1; 355 } 356 return (pri); 357 } 358} 359 360void 361IpInput(struct mbuf * bp) 362{ /* IN: Pointer to IP pakcet */ 363 u_char *cp; 364 struct mbuf *wp; 365 int nb, nw; 366 u_char tunbuff[MAX_MRU]; 367 368 cp = tunbuff; 369 nb = 0; 370 for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 371 memcpy(cp, MBUF_CTOP(wp), wp->cnt); 372 cp += wp->cnt; 373 nb += wp->cnt; 374 } 375 376 if (mode & MODE_ALIAS) { 377 int iresult; 378 char *fptr; 379 380 iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff); 381 nb = ntohs(((struct ip *) tunbuff)->ip_len); 382 383 if (nb > MAX_MRU) { 384 LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 385 pfree(bp); 386 return; 387 } 388 if (iresult == PKT_ALIAS_OK 389 || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 390 if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 391 pfree(bp); 392 return; 393 } 394 ipInOctets += nb; 395 396 nb = ntohs(((struct ip *) tunbuff)->ip_len); 397 nw = write(tun_out, tunbuff, nb); 398 if (nw != nb) 399 if (nw == -1) 400 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 401 strerror(errno)); 402 else 403 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 404 405 if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 406 while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) { 407 VarPacketAliasFragmentIn(tunbuff, fptr); 408 nb = ntohs(((struct ip *) fptr)->ip_len); 409 nw = write(tun_out, fptr, nb); 410 if (nw != nb) 411 if (nw == -1) 412 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 413 strerror(errno)); 414 else 415 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 416 free(fptr); 417 } 418 } 419 } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 420 nb = ntohs(((struct ip *) tunbuff)->ip_len); 421 fptr = malloc(nb); 422 if (fptr == NULL) 423 LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 424 else { 425 memcpy(fptr, tunbuff, nb); 426 VarPacketAliasSaveFragment(fptr); 427 } 428 } 429 } else { /* no aliasing */ 430 if (PacketCheck(tunbuff, nb, FL_IN) < 0) { 431 pfree(bp); 432 return; 433 } 434 ipInOctets += nb; 435 nw = write(tun_out, tunbuff, nb); 436 if (nw != nb) 437 if (nw == -1) 438 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 439 else 440 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 441 } 442 pfree(bp); 443 444 RestartIdleTimer(); 445} 446 447static struct mqueue IpOutputQueues[PRI_FAST + 1]; 448 449void 450IpEnqueue(int pri, char *ptr, int count) 451{ 452 struct mbuf *bp; 453 454 bp = mballoc(count, MB_IPQ); 455 memcpy(MBUF_CTOP(bp), ptr, count); 456 Enqueue(&IpOutputQueues[pri], bp); 457} 458 459#if 0 460int 461IsIpEnqueued() 462{ 463 struct mqueue *queue; 464 int exist = 0; 465 466 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 467 if (queue->qlen > 0) { 468 exist = 1; 469 break; 470 } 471 } 472 return (exist); 473} 474#endif 475 476void 477IpStartOutput() 478{ 479 struct mqueue *queue; 480 struct mbuf *bp; 481 int cnt; 482 483 if (IpcpFsm.state != ST_OPENED) 484 return; 485 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 486 if (queue->top) { 487 bp = Dequeue(queue); 488 if (bp) { 489 cnt = plength(bp); 490 SendPppFrame(bp); 491 RestartIdleTimer(); 492 ipOutOctets += cnt; 493 break; 494 } 495 } 496 } 497} 498