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