ip.c revision 32039
1119026Sume/* 266776Skris * PPP IP Protocol Interface 355163Sshin * 455163Sshin * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 555163Sshin * 662632Skris * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 755163Sshin * 855163Sshin * Redistribution and use in source and binary forms are permitted 955163Sshin * provided that the above copyright notice and this paragraph are 1055163Sshin * duplicated in all such forms and that any documentation, 1155163Sshin * advertising materials, and other materials related to such 1255163Sshin * distribution and use acknowledge that the software was developed 1355163Sshin * by the Internet Initiative Japan. The name of the 1455163Sshin * IIJ may not be used to endorse or promote products derived 1555163Sshin * from this software without specific prior written permission. 1655163Sshin * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1755163Sshin * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1862632Skris * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1955163Sshin * 2055163Sshin * $Id: ip.c,v 1.33 1997/12/24 09:29:01 brian Exp $ 2155163Sshin * 2255163Sshin * TODO: 2355163Sshin * o Return ICMP message for filterd packet 2455163Sshin * and optionaly record it into log. 2555163Sshin */ 2655163Sshin#include <sys/param.h> 2755163Sshin#include <sys/time.h> 2855163Sshin#include <sys/select.h> 2955163Sshin#include <sys/socket.h> 3055163Sshin#include <netinet/in.h> 3155163Sshin#include <netinet/in_systm.h> 3255163Sshin#include <netinet/ip.h> 3355163Sshin#include <netinet/ip_icmp.h> 34222732Shrs#include <netinet/udp.h> 35222732Shrs#include <netinet/tcp.h> 36222732Shrs#include <arpa/inet.h> 37222732Shrs#include <net/if.h> 38222732Shrs#ifdef __FreeBSD__ 39222732Shrs#include <net/if_var.h> 40225520Shrs#endif 41225520Shrs#include <net/if_tun.h> 42222732Shrs 43222732Shrs#ifndef NOALIAS 44222732Shrs#include <alias.h> 45222732Shrs#endif 46253970Shrs#include <errno.h> 47222732Shrs#include <stdio.h> 48222732Shrs#include <stdlib.h> 49222732Shrs#include <string.h> 50222732Shrs#include <termios.h> 51222861Shrs#include <unistd.h> 52222861Shrs 53222861Shrs#include "command.h" 54222861Shrs#include "mbuf.h" 55222861Shrs#include "log.h" 56222861Shrs#include "defs.h" 57222861Shrs#include "timer.h" 58222861Shrs#include "fsm.h" 59222861Shrs#include "lcpproto.h" 60222861Shrs#include "hdlc.h" 6155163Sshin#include "loadalias.h" 62222732Shrs#include "vars.h" 6355163Sshin#include "filter.h" 6455163Sshin#include "os.h" 65225520Shrs#include "ipcp.h" 66119026Sume#include "vjcomp.h" 6755163Sshin#include "lcp.h" 68118664Sume#include "modem.h" 6955163Sshin#include "tun.h" 7055163Sshin#include "ip.h" 71118661Sume 72118661Sumestatic struct pppTimer IdleTimer; 7355163Sshin 7455163Sshinstatic void 7555163SshinIdleTimeout(void *v) 76253970Shrs{ 77253970Shrs LogPrintf(LogPHASE, "Idle timer expired.\n"); 7862632Skris reconnect(RECON_FALSE); 79222861Shrs LcpClose(); 80222861Shrs} 81222861Shrs 82222861Shrs/* 8355163Sshin * Start Idle timer. If timeout is reached, we call LcpClose() to 8455163Sshin * close LCP and link. 85222861Shrs */ 8655163Sshinvoid 8755163SshinStartIdleTimer() 8855163Sshin{ 8955163Sshin if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 9055163Sshin StopTimer(&IdleTimer); 9155163Sshin IdleTimer.func = IdleTimeout; 9262632Skris IdleTimer.load = VarIdleTimeout * SECTICKS; 9362632Skris IdleTimer.state = TIMER_STOPPED; 9462632Skris StartTimer(&IdleTimer); 9562632Skris } 9662632Skris} 9755163Sshin 98222732Shrsvoid 99222732ShrsUpdateIdleTimer() 100222732Shrs{ 101225520Shrs if (OsLinkIsUp()) 102222732Shrs StartIdleTimer(); 103222732Shrs} 104222732Shrs 105222732Shrsvoid 106222732ShrsStopIdleTimer() 107222732Shrs{ 108222732Shrs StopTimer(&IdleTimer); 109222732Shrs} 110222732Shrs 111222732Shrs/* 112222732Shrs * If any IP layer traffic is detected, refresh IdleTimer. 113222732Shrs */ 114222732Shrsstatic void 115222732ShrsRestartIdleTimer(void) 116222732Shrs{ 117222732Shrs if (!(mode & (MODE_DEDICATED | MODE_DDIAL)) && ipKeepAlive) { 118222732Shrs StartTimer(&IdleTimer); 119222732Shrs ipIdleSecs = 0; 120222732Shrs } 121222732Shrs} 122222732Shrs 123222732Shrsstatic const u_short interactive_ports[32] = { 124222732Shrs 544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 125222732Shrs 0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543, 126222732Shrs}; 127253970Shrs 128253970Shrs#define INTERACTIVE(p) (interactive_ports[(p) & 0x1F] == (p)) 129253970Shrs 130253970Shrsstatic const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" }; 131253970Shrs 132253970Shrsstatic const char *Direction[] = {"INP", "OUT", "OUT", "IN/OUT"}; 133253970Shrsstatic struct filterent *Filters[] = {ifilters, ofilters, dfilters, afilters}; 134253970Shrs 135253970Shrsstatic int 136253970ShrsPortMatch(int op, u_short pport, u_short rport) 137253970Shrs{ 138253970Shrs switch (op) { 139253970Shrs case OP_EQ: 140253970Shrs return (pport == rport); 141253970Shrs case OP_GT: 142253970Shrs return (pport > rport); 143253970Shrs case OP_LT: 144253970Shrs return (pport < rport); 145253970Shrs default: 146253970Shrs return (0); 147253970Shrs } 148253970Shrs} 149253970Shrs 15055163Sshin/* 151253970Shrs * Check a packet against with defined filters 15255163Sshin */ 153119026Sumestatic int 154197141ShrsFilterCheck(struct ip * pip, int direction) 155225520Shrs{ 156222732Shrs struct filterent *fp = Filters[direction]; 157222732Shrs int gotinfo, cproto, estab, n; 158173412Skevlo struct tcphdr *th; 159173412Skevlo struct udphdr *uh; 160173412Skevlo struct icmp *ih; 161222861Shrs char *ptop; 162173412Skevlo u_short sport, dport; 163173412Skevlo 16466776Skris if (fp->action) { 165173412Skevlo cproto = gotinfo = estab = 0; 166222732Shrs sport = dport = 0; 16755163Sshin for (n = 0; n < MAXFILTERS; n++) { 16855163Sshin if (fp->action) { 169173412Skevlo /* permit fragments on in and out filter */ 170173412Skevlo if ((direction == FL_IN || direction == FL_OUT) && 171173412Skevlo (ntohs(pip->ip_off) & IP_OFFMASK) != 0) { 172173412Skevlo return (A_PERMIT); 173173412Skevlo } 174173412Skevlo LogPrintf(LogDEBUG, "rule = %d\n", n); 175173412Skevlo if ((pip->ip_src.s_addr & fp->smask.s_addr) == 176173412Skevlo (fp->saddr.s_addr & fp->smask.s_addr) && 17755163Sshin (pip->ip_dst.s_addr & fp->dmask.s_addr) == 17855163Sshin (fp->daddr.s_addr & fp->dmask.s_addr)) { 179254462Shrs if (fp->proto) { 180173412Skevlo if (!gotinfo) { 181173412Skevlo ptop = (char *) pip + (pip->ip_hl << 2); 182173412Skevlo 18355163Sshin switch (pip->ip_p) { 18455163Sshin case IPPROTO_ICMP: 185173412Skevlo cproto = P_ICMP; 186173412Skevlo ih = (struct icmp *) ptop; 18755163Sshin sport = ih->icmp_type; 18855163Sshin estab = 1; 189204407Suqs break; 190253970Shrs case IPPROTO_UDP: 19178064Sume cproto = P_UDP; 19278064Sume uh = (struct udphdr *) ptop; 193173412Skevlo sport = ntohs(uh->uh_sport); 194173412Skevlo 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) && direction != FL_DIAL; 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