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