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