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