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