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