ip.c revision 35449
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.39 1998/03/13 01:36:09 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 <sys/time.h> 28#include <sys/socket.h> 29#include <net/if.h> 30#include <net/if_tun.h> 31#include <netinet/in.h> 32#include <netinet/in_systm.h> 33#include <netinet/ip.h> 34#include <netinet/ip_icmp.h> 35#include <netinet/udp.h> 36#include <netinet/tcp.h> 37#include <arpa/inet.h> 38 39#ifndef NOALIAS 40#include <alias.h> 41#endif 42#include <errno.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <termios.h> 47#include <unistd.h> 48 49#include "command.h" 50#include "mbuf.h" 51#include "log.h" 52#include "defs.h" 53#include "timer.h" 54#include "fsm.h" 55#include "hdlc.h" 56#include "loadalias.h" 57#include "vars.h" 58#include "filter.h" 59#include "os.h" 60#include "ipcp.h" 61#include "vjcomp.h" 62#include "lcp.h" 63#include "modem.h" 64#include "tun.h" 65#include "ip.h" 66 67static struct pppTimer IdleTimer; 68 69static void 70IdleTimeout(void *v) 71{ 72 LogPrintf(LogPHASE, "Idle timer expired.\n"); 73 reconnect(RECON_FALSE); 74 LcpClose(); 75} 76 77/* 78 * Start Idle timer. If timeout is reached, we call LcpClose() to 79 * close LCP and link. 80 */ 81void 82StartIdleTimer() 83{ 84 static time_t IdleStarted; 85 86 if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 87 StopTimer(&IdleTimer); 88 IdleTimer.func = IdleTimeout; 89 IdleTimer.load = VarIdleTimeout * SECTICKS; 90 IdleTimer.state = TIMER_STOPPED; 91 time(&IdleStarted); 92 IdleTimer.arg = (void *)&IdleStarted; 93 StartTimer(&IdleTimer); 94 } 95} 96 97void 98UpdateIdleTimer() 99{ 100 if (OsLinkIsUp()) 101 StartIdleTimer(); 102} 103 104void 105StopIdleTimer() 106{ 107 StopTimer(&IdleTimer); 108} 109 110int 111RemainingIdleTime() 112{ 113 if (VarIdleTimeout == 0 || IdleTimer.state != TIMER_RUNNING || 114 IdleTimer.arg == NULL) 115 return -1; 116 return VarIdleTimeout - (time(NULL) - *(time_t *)IdleTimer.arg); 117} 118 119/* 120 * If any IP layer traffic is detected, refresh IdleTimer. 121 */ 122static void 123RestartIdleTimer(void) 124{ 125 if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 126 time((time_t *)IdleTimer.arg); 127 StartTimer(&IdleTimer); 128 } 129} 130 131static const u_short interactive_ports[32] = { 132 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 133 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 134}; 135 136#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 137 138static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 139 140static const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 141static struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 142 143static int 144PortMatch(int op, u_short pport, u_short rport) 145{ 146 switch (op) { 147 case OP_EQ: 148 return (pport == rport); 149 case OP_GT: 150 return (pport > rport); 151 case OP_LT: 152 return (pport < rport); 153 default: 154 return (0); 155 } 156} 157 158/* 159 * Check a packet against with defined filters 160 */ 161static int 162FilterCheck(struct ip * pip, int direction) 163{ 164 struct filterent *fp = Filters[direction]; 165 int gotinfo, cproto, estab, n; 166 struct tcphdr *th; 167 struct udphdr *uh; 168 struct icmp *ih; 169 char *ptop; 170 u_short sport, dport; 171 172 if (fp->action) { 173 cproto = gotinfo = estab = 0; 174 sport = dport = 0; 175 for (n = 0; n < MAXFILTERS; n++) { 176 if (fp->action) { 177 /* permit fragments on in and out filter */ 178 if ((direction == FL_IN || direction == FL_OUT) && 179 (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 180 return (A_PERMIT); 181 } 182 LogPrintf(LogDEBUG, "rule = %d\n", n); 183 if ((pip->ip_src.s_addr & fp->smask.s_addr) == 184 (fp->saddr.s_addr & fp->smask.s_addr) && 185 (pip->ip_dst.s_addr & fp->dmask.s_addr) == 186 (fp->daddr.s_addr & fp->dmask.s_addr)) { 187 if (fp->proto) { 188 if (!gotinfo) { 189 ptop = (char *) pip + (pip->ip_hl << 2); 190 191 switch (pip->ip_p) { 192 case IPPROTO_ICMP: 193 cproto = P_ICMP; 194 ih = (struct icmp *) ptop; 195 sport = ih->icmp_type; 196 estab = 1; 197 break; 198 case IPPROTO_UDP: 199 cproto = P_UDP; 200 uh = (struct udphdr *) ptop; 201 sport = ntohs(uh->uh_sport); 202 dport = ntohs(uh->uh_dport); 203 estab = 1; 204 break; 205 case IPPROTO_TCP: 206 cproto = P_TCP; 207 th = (struct tcphdr *) ptop; 208 sport = ntohs(th->th_sport); 209 dport = ntohs(th->th_dport); 210 estab = (th->th_flags & TH_ACK); 211 if (estab == 0) 212 LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n", 213 th->th_flags, sport, dport); 214 break; 215 default: 216 return (A_DENY);/* We'll block unknown type of packet */ 217 } 218 gotinfo = 1; 219 LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d," 220 " dstop = %d, estab = %d\n", direction, cproto, 221 fp->opt.srcop, fp->opt.dstop, estab); 222 } 223 LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d," 224 " dport = %d\n", n, cproto, sport, dport); 225 LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action); 226 227 if (cproto == fp->proto) { 228 if ((fp->opt.srcop == OP_NONE || 229 PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) 230 && 231 (fp->opt.dstop == OP_NONE || 232 PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) 233 && 234 (fp->opt.estab == 0 || estab)) { 235 return (fp->action); 236 } 237 } 238 } else { 239 /* Address is mached. Make a decision. */ 240 LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action); 241 return (fp->action); 242 } 243 } 244 } 245 fp++; 246 } 247 return (A_DENY); /* No rule is mached. Deny this packet */ 248 } 249 return (A_PERMIT); /* No rule is given. Permit this packet */ 250} 251 252static void 253IcmpError(struct ip * pip, int code) 254{ 255#ifdef notdef 256 struct mbuf *bp; 257 258 if (pip->ip_p != IPPROTO_ICMP) { 259 bp = mballoc(cnt, MB_IPIN); 260 memcpy(MBUF_CTOP(bp), ptr, cnt); 261 SendPppFrame(bp); 262 RestartIdleTimer(); 263 IpcpAddOutOctets(cnt); 264 } 265#endif 266} 267 268/* 269 * For debugging aid. 270 */ 271int 272PacketCheck(char *cp, int nb, int direction) 273{ 274 struct ip *pip; 275 struct tcphdr *th; 276 struct udphdr *uh; 277 struct icmp *icmph; 278 char *ptop; 279 int mask, len, n; 280 int pri = PRI_NORMAL; 281 int logit, loglen; 282 static char logbuf[200]; 283 284 logit = LogIsKept(LogTCPIP) && direction != FL_DIAL; 285 loglen = 0; 286 287 pip = (struct ip *) cp; 288 289 if (logit && loglen < sizeof logbuf) { 290 snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", 291 Direction[direction]); 292 loglen += strlen(logbuf + loglen); 293 } 294 ptop = (cp + (pip->ip_hl << 2)); 295 296 switch (pip->ip_p) { 297 case IPPROTO_ICMP: 298 if (logit && loglen < sizeof logbuf) { 299 icmph = (struct icmp *) ptop; 300 snprintf(logbuf + loglen, sizeof logbuf - loglen, 301 "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type); 302 loglen += strlen(logbuf + loglen); 303 snprintf(logbuf + loglen, sizeof logbuf - loglen, 304 "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type); 305 loglen += strlen(logbuf + loglen); 306 } 307 break; 308 case IPPROTO_UDP: 309 if (logit && loglen < sizeof logbuf) { 310 uh = (struct udphdr *) ptop; 311 snprintf(logbuf + loglen, sizeof logbuf - loglen, 312 "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport)); 313 loglen += strlen(logbuf + loglen); 314 snprintf(logbuf + loglen, sizeof logbuf - loglen, 315 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport)); 316 loglen += strlen(logbuf + loglen); 317 } 318 break; 319 case IPPROTO_TCP: 320 th = (struct tcphdr *) ptop; 321 if (pip->ip_tos == IPTOS_LOWDELAY) 322 pri = PRI_FAST; 323 else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) { 324 if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport))) 325 pri = PRI_FAST; 326 } 327 if (logit && loglen < sizeof logbuf) { 328 len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2); 329 snprintf(logbuf + loglen, sizeof logbuf - loglen, 330 "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport)); 331 loglen += strlen(logbuf + loglen); 332 snprintf(logbuf + loglen, sizeof logbuf - loglen, 333 "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport)); 334 loglen += strlen(logbuf + loglen); 335 n = 0; 336 for (mask = TH_FIN; mask != 0x40; mask <<= 1) { 337 if (th->th_flags & mask) { 338 snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]); 339 loglen += strlen(logbuf + loglen); 340 } 341 n++; 342 } 343 snprintf(logbuf + loglen, sizeof logbuf - loglen, 344 " seq:%x ack:%x (%d/%d)", 345 ntohl(th->th_seq), ntohl(th->th_ack), len, nb); 346 loglen += strlen(logbuf + loglen); 347 if ((th->th_flags & TH_SYN) && nb > 40) { 348 u_short *sp; 349 350 ptop += 20; 351 sp = (u_short *) ptop; 352 if (ntohs(sp[0]) == 0x0204) { 353 snprintf(logbuf + loglen, sizeof logbuf - loglen, 354 " MSS = %d", ntohs(sp[1])); 355 loglen += strlen(logbuf + loglen); 356 } 357 } 358 } 359 break; 360 } 361 362 if ((FilterCheck(pip, direction) & A_DENY)) { 363 if (logit) 364 LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf); 365 if (direction == 0) 366 IcmpError(pip, pri); 367 return (-1); 368 } else { 369 if (FilterCheck(pip, FL_KEEP) & A_DENY) { /* Check Keep Alive filter */ 370 if (logit) 371 LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf); 372 ipKeepAlive = 0; 373 } else { 374 if (logit) 375 LogPrintf(LogTCPIP, "%s\n", logbuf); 376 ipKeepAlive = 1; 377 } 378 return (pri); 379 } 380} 381 382void 383IpInput(struct mbuf * bp) 384{ /* IN: Pointer to IP pakcet */ 385 u_char *cp; 386 struct mbuf *wp; 387 int nb, nw; 388 struct tun_data tun; 389 390 tun_fill_header(tun, AF_INET); 391 cp = tun.data; 392 nb = 0; 393 for (wp = bp; wp; wp = wp->next) { /* Copy to contiguous region */ 394 if (sizeof tun.data - (cp - tun.data) < wp->cnt) { 395 LogPrintf(LogERROR, "IpInput: Packet too large (%d) - dropped\n", 396 plength(bp)); 397 pfree(bp); 398 return; 399 } 400 memcpy(cp, MBUF_CTOP(wp), wp->cnt); 401 cp += wp->cnt; 402 nb += wp->cnt; 403 } 404 405#ifndef NOALIAS 406 if (mode & MODE_ALIAS) { 407 struct tun_data *frag; 408 int iresult; 409 char *fptr; 410 411 iresult = VarPacketAliasIn(tun.data, sizeof tun.data); 412 nb = ntohs(((struct ip *) tun.data)->ip_len); 413 414 if (nb > MAX_MRU) { 415 LogPrintf(LogERROR, "IpInput: Problem with IP header length\n"); 416 pfree(bp); 417 return; 418 } 419 if (iresult == PKT_ALIAS_OK 420 || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 421 if (PacketCheck(tun.data, nb, FL_IN) < 0) { 422 pfree(bp); 423 return; 424 } 425 IpcpAddInOctets(nb); 426 427 nb = ntohs(((struct ip *) tun.data)->ip_len); 428 nb += sizeof tun - sizeof tun.data; 429 nw = write(tun_out, &tun, nb); 430 if (nw != nb) { 431 if (nw == -1) 432 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 433 strerror(errno)); 434 else 435 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 436 } 437 438 if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 439 while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) { 440 VarPacketAliasFragmentIn(tun.data, fptr); 441 nb = ntohs(((struct ip *) fptr)->ip_len); 442 frag = (struct tun_data *) 443 ((char *)fptr - sizeof tun + sizeof tun.data); 444 nb += sizeof tun - sizeof tun.data; 445 nw = write(tun_out, frag, nb); 446 if (nw != nb) { 447 if (nw == -1) 448 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 449 strerror(errno)); 450 else 451 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 452 } 453 free(frag); 454 } 455 } 456 } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 457 nb = ntohs(((struct ip *) tun.data)->ip_len); 458 nb += sizeof tun - sizeof tun.data; 459 frag = (struct tun_data *)malloc(nb); 460 if (frag == NULL) 461 LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 462 else { 463 tun_fill_header(*frag, AF_INET); 464 memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data); 465 VarPacketAliasSaveFragment(frag->data); 466 } 467 } 468 } else 469#endif /* #ifndef NOALIAS */ 470 { /* no aliasing */ 471 if (PacketCheck(tun.data, nb, FL_IN) < 0) { 472 pfree(bp); 473 return; 474 } 475 IpcpAddInOctets(nb); 476 nb += sizeof tun - sizeof tun.data; 477 nw = write(tun_out, &tun, nb); 478 if (nw != nb) { 479 if (nw == -1) 480 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 481 else 482 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 483 } 484 } 485 pfree(bp); 486 487 RestartIdleTimer(); 488} 489 490static struct mqueue IpOutputQueues[PRI_FAST + 1]; 491 492void 493IpEnqueue(int pri, char *ptr, int count) 494{ 495 struct mbuf *bp; 496 497 bp = mballoc(count, MB_IPQ); 498 memcpy(MBUF_CTOP(bp), ptr, count); 499 Enqueue(&IpOutputQueues[pri], bp); 500} 501 502#if 0 503int 504IsIpEnqueued() 505{ 506 struct mqueue *queue; 507 int exist = 0; 508 509 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 510 if (queue->qlen > 0) { 511 exist = 1; 512 break; 513 } 514 } 515 return (exist); 516} 517#endif 518 519void 520IpStartOutput() 521{ 522 struct mqueue *queue; 523 struct mbuf *bp; 524 int cnt; 525 526 if (IpcpFsm.state != ST_OPENED) 527 return; 528 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 529 if (queue->top) { 530 bp = Dequeue(queue); 531 if (bp) { 532 cnt = plength(bp); 533 SendPppFrame(bp); 534 RestartIdleTimer(); 535 IpcpAddOutOctets(cnt); 536 break; 537 } 538 } 539 } 540} 541