ip.c revision 32663
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.37 1998/01/11 17:53:18 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 if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) { 438 while ((fptr = VarPacketAliasGetFragment(tun.data)) != NULL) { 439 VarPacketAliasFragmentIn(tun.data, fptr); 440 nb = ntohs(((struct ip *) fptr)->ip_len); 441 frag = (struct tun_data *) 442 ((char *)fptr - sizeof tun + sizeof tun.data); 443 nb += sizeof tun - sizeof tun.data; 444 nw = write(tun_out, frag, nb); 445 if (nw != nb) 446 if (nw == -1) 447 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, 448 strerror(errno)); 449 else 450 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 451 free(frag); 452 } 453 } 454 } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) { 455 nb = ntohs(((struct ip *) tun.data)->ip_len); 456 nb += sizeof tun - sizeof tun.data; 457 frag = (struct tun_data *)malloc(nb); 458 if (frag == NULL) 459 LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n"); 460 else { 461 tun_fill_header(*frag, AF_INET); 462 memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data); 463 VarPacketAliasSaveFragment(frag->data); 464 } 465 } 466 } else 467#endif /* #ifndef NOALIAS */ 468 { /* no aliasing */ 469 if (PacketCheck(tun.data, nb, FL_IN) < 0) { 470 pfree(bp); 471 return; 472 } 473 IpcpAddInOctets(nb); 474 nb += sizeof tun - sizeof tun.data; 475 nw = write(tun_out, &tun, nb); 476 if (nw != nb) 477 if (nw == -1) 478 LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno)); 479 else 480 LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw); 481 } 482 pfree(bp); 483 484 RestartIdleTimer(); 485} 486 487static struct mqueue IpOutputQueues[PRI_FAST + 1]; 488 489void 490IpEnqueue(int pri, char *ptr, int count) 491{ 492 struct mbuf *bp; 493 494 bp = mballoc(count, MB_IPQ); 495 memcpy(MBUF_CTOP(bp), ptr, count); 496 Enqueue(&IpOutputQueues[pri], bp); 497} 498 499#if 0 500int 501IsIpEnqueued() 502{ 503 struct mqueue *queue; 504 int exist = 0; 505 506 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 507 if (queue->qlen > 0) { 508 exist = 1; 509 break; 510 } 511 } 512 return (exist); 513} 514#endif 515 516void 517IpStartOutput() 518{ 519 struct mqueue *queue; 520 struct mbuf *bp; 521 int cnt; 522 523 if (IpcpFsm.state != ST_OPENED) 524 return; 525 for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) { 526 if (queue->top) { 527 bp = Dequeue(queue); 528 if (bp) { 529 cnt = plength(bp); 530 SendPppFrame(bp); 531 RestartIdleTimer(); 532 IpcpAddOutOctets(cnt); 533 break; 534 } 535 } 536 } 537} 538