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