ip.c revision 31143
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.28 1997/11/12 19:48:45 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) ==
168	    (fp->saddr.s_addr & fp->smask.s_addr) &&
169	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
170	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
171	  if (fp->proto) {
172	    if (!gotinfo) {
173	      ptop = (char *) pip + (pip->ip_hl << 2);
174
175	      switch (pip->ip_p) {
176	      case IPPROTO_ICMP:
177		cproto = P_ICMP;
178		ih = (struct icmp *) ptop;
179		sport = ih->icmp_type;
180		estab = 1;
181		break;
182	      case IPPROTO_UDP:
183		cproto = P_UDP;
184		uh = (struct udphdr *) ptop;
185		sport = ntohs(uh->uh_sport);
186		dport = ntohs(uh->uh_dport);
187		estab = 1;
188		break;
189	      case IPPROTO_TCP:
190		cproto = P_TCP;
191		th = (struct tcphdr *) ptop;
192		sport = ntohs(th->th_sport);
193		dport = ntohs(th->th_dport);
194		estab = (th->th_flags & TH_ACK);
195		if (estab == 0)
196		  LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
197			    th->th_flags, sport, dport);
198		break;
199	      default:
200		return (A_DENY);/* We'll block unknown type of packet */
201	      }
202	      gotinfo = 1;
203	      LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
204			" dstop = %d, estab = %d\n", direction, cproto,
205			fp->opt.srcop, fp->opt.dstop, estab);
206	    }
207	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
208		      " dport = %d\n", n, cproto, sport, dport);
209	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
210
211	    if (cproto == fp->proto) {
212	      if ((fp->opt.srcop == OP_NONE ||
213		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
214		  &&
215		  (fp->opt.dstop == OP_NONE ||
216		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
217		  &&
218		  (fp->opt.estab == 0 || estab)) {
219		return (fp->action);
220	      }
221	    }
222	  } else {
223	    /* Address is mached. Make a decision. */
224	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
225	    return (fp->action);
226	  }
227	}
228      }
229      fp++;
230    }
231    return (A_DENY);		/* No rule is mached. Deny this packet */
232  }
233  return (A_PERMIT);		/* No rule is given. Permit this packet */
234}
235
236static void
237IcmpError(struct ip * pip, int code)
238{
239#ifdef notdef
240  struct mbuf *bp;
241
242  if (pip->ip_p != IPPROTO_ICMP) {
243    bp = mballoc(cnt, MB_IPIN);
244    memcpy(MBUF_CTOP(bp), ptr, cnt);
245    SendPppFrame(bp);
246    RestartIdleTimer();
247    ipOutOctets += cnt;
248  }
249#endif
250}
251
252/*
253 *  For debugging aid.
254 */
255int
256PacketCheck(char *cp, int nb, int direction)
257{
258  struct ip *pip;
259  struct tcphdr *th;
260  struct udphdr *uh;
261  struct icmp *icmph;
262  char *ptop;
263  int mask, len, n;
264  int pri = PRI_NORMAL;
265  int logit, loglen;
266  static char logbuf[200];
267
268  logit = LogIsKept(LogTCPIP);
269  loglen = 0;
270
271  pip = (struct ip *) cp;
272
273  if (logit && loglen < sizeof logbuf) {
274    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ",
275	     Direction[direction]);
276    loglen += strlen(logbuf + loglen);
277  }
278  ptop = (cp + (pip->ip_hl << 2));
279
280  switch (pip->ip_p) {
281  case IPPROTO_ICMP:
282    if (logit && loglen < sizeof logbuf) {
283      icmph = (struct icmp *) ptop;
284      snprintf(logbuf + loglen, sizeof logbuf - loglen,
285	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
286      loglen += strlen(logbuf + loglen);
287      snprintf(logbuf + loglen, sizeof logbuf - loglen,
288	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
289      loglen += strlen(logbuf + loglen);
290    }
291    break;
292  case IPPROTO_UDP:
293    if (logit && loglen < sizeof logbuf) {
294      uh = (struct udphdr *) ptop;
295      snprintf(logbuf + loglen, sizeof logbuf - loglen,
296	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
297      loglen += strlen(logbuf + loglen);
298      snprintf(logbuf + loglen, sizeof logbuf - loglen,
299	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
300      loglen += strlen(logbuf + loglen);
301    }
302    break;
303  case IPPROTO_TCP:
304    th = (struct tcphdr *) ptop;
305    if (pip->ip_tos == IPTOS_LOWDELAY)
306      pri = PRI_FAST;
307    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
308      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
309	pri = PRI_FAST;
310    }
311    if (logit && loglen < sizeof logbuf) {
312      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
313      snprintf(logbuf + loglen, sizeof logbuf - loglen,
314	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
315      loglen += strlen(logbuf + loglen);
316      snprintf(logbuf + loglen, sizeof logbuf - loglen,
317	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
318      loglen += strlen(logbuf + loglen);
319      n = 0;
320      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
321	if (th->th_flags & mask) {
322	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
323	  loglen += strlen(logbuf + loglen);
324	}
325	n++;
326      }
327      snprintf(logbuf + loglen, sizeof logbuf - loglen,
328	       "  seq:%x  ack:%x (%d/%d)",
329	       ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
330      loglen += strlen(logbuf + loglen);
331      if ((th->th_flags & TH_SYN) && nb > 40) {
332	u_short *sp;
333
334	ptop += 20;
335	sp = (u_short *) ptop;
336	if (ntohs(sp[0]) == 0x0204) {
337	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
338		   " MSS = %d", ntohs(sp[1]));
339	  loglen += strlen(logbuf + loglen);
340	}
341      }
342    }
343    break;
344  }
345
346  if ((FilterCheck(pip, direction) & A_DENY)) {
347    if (logit)
348      LogPrintf(LogTCPIP, "%s - BLOCKED\n", logbuf);
349    if (direction == 0)
350      IcmpError(pip, pri);
351    return (-1);
352  } else {
353    if (FilterCheck(pip, FL_KEEP) & A_DENY) {	/* Check Keep Alive filter */
354      if (logit)
355        LogPrintf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
356      ipKeepAlive = 0;
357    } else {
358      if (logit)
359        LogPrintf(LogTCPIP, "%s\n", logbuf);
360      ipKeepAlive = 1;
361    }
362    return (pri);
363  }
364}
365
366void
367IpInput(struct mbuf * bp)
368{				/* IN: Pointer to IP pakcet */
369  u_char *cp;
370  struct mbuf *wp;
371  int nb, nw;
372  u_char tunbuff[MAX_MRU];
373
374  cp = tunbuff;
375  nb = 0;
376  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
377    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
378    cp += wp->cnt;
379    nb += wp->cnt;
380  }
381
382  if (mode & MODE_ALIAS) {
383    int iresult;
384    char *fptr;
385
386    iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff);
387    nb = ntohs(((struct ip *) tunbuff)->ip_len);
388
389    if (nb > MAX_MRU) {
390      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
391      pfree(bp);
392      return;
393    }
394    if (iresult == PKT_ALIAS_OK
395	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
396      if (PacketCheck(tunbuff, nb, FL_IN) < 0) {
397	pfree(bp);
398	return;
399      }
400      ipInOctets += nb;
401
402      nb = ntohs(((struct ip *) tunbuff)->ip_len);
403      nw = write(tun_out, tunbuff, nb);
404      if (nw != nb)
405        if (nw == -1)
406	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
407                    strerror(errno));
408        else
409	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
410
411      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
412	while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) {
413	  VarPacketAliasFragmentIn(tunbuff, fptr);
414	  nb = ntohs(((struct ip *) fptr)->ip_len);
415	  nw = write(tun_out, fptr, 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	  free(fptr);
423	}
424      }
425    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
426      nb = ntohs(((struct ip *) tunbuff)->ip_len);
427      fptr = malloc(nb);
428      if (fptr == NULL)
429	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
430      else {
431	memcpy(fptr, tunbuff, nb);
432	VarPacketAliasSaveFragment(fptr);
433      }
434    }
435  } else {			/* no aliasing */
436    if (PacketCheck(tunbuff, nb, FL_IN) < 0) {
437      pfree(bp);
438      return;
439    }
440    ipInOctets += nb;
441    nw = write(tun_out, tunbuff, nb);
442    if (nw != nb)
443      if (nw == -1)
444	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
445      else
446        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
447  }
448  pfree(bp);
449
450  RestartIdleTimer();
451}
452
453static struct mqueue IpOutputQueues[PRI_FAST + 1];
454
455void
456IpEnqueue(int pri, char *ptr, int count)
457{
458  struct mbuf *bp;
459
460  bp = mballoc(count, MB_IPQ);
461  memcpy(MBUF_CTOP(bp), ptr, count);
462  Enqueue(&IpOutputQueues[pri], bp);
463}
464
465#if 0
466int
467IsIpEnqueued()
468{
469  struct mqueue *queue;
470  int exist = 0;
471
472  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
473    if (queue->qlen > 0) {
474      exist = 1;
475      break;
476    }
477  }
478  return (exist);
479}
480#endif
481
482void
483IpStartOutput()
484{
485  struct mqueue *queue;
486  struct mbuf *bp;
487  int cnt;
488
489  if (IpcpFsm.state != ST_OPENED)
490    return;
491  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
492    if (queue->top) {
493      bp = Dequeue(queue);
494      if (bp) {
495	cnt = plength(bp);
496	SendPppFrame(bp);
497	RestartIdleTimer();
498	ipOutOctets += cnt;
499	break;
500      }
501    }
502  }
503}
504