ip.c revision 30733
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.26 1997/10/26 01:02:52 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 (logit)
345    LogPrintf(LogTCPIP, "%s\n", logbuf);
346
347  if ((FilterCheck(pip, direction) & A_DENY)) {
348    LogPrintf(LogDEBUG, "blocked.\n");
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      ipKeepAlive = 0;
355    } else {
356      ipKeepAlive = 1;
357    }
358    return (pri);
359  }
360}
361
362void
363IpInput(struct mbuf * bp)
364{				/* IN: Pointer to IP pakcet */
365  u_char *cp;
366  struct mbuf *wp;
367  int nb, nw;
368  u_char tunbuff[MAX_MRU];
369
370  cp = tunbuff;
371  nb = 0;
372  for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
373    memcpy(cp, MBUF_CTOP(wp), wp->cnt);
374    cp += wp->cnt;
375    nb += wp->cnt;
376  }
377
378  if (mode & MODE_ALIAS) {
379    int iresult;
380    char *fptr;
381
382    iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff);
383    nb = ntohs(((struct ip *) tunbuff)->ip_len);
384
385    if (nb > MAX_MRU) {
386      LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
387      pfree(bp);
388      return;
389    }
390    if (iresult == PKT_ALIAS_OK
391	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
392      if (PacketCheck(tunbuff, nb, FL_IN) < 0) {
393	pfree(bp);
394	return;
395      }
396      ipInOctets += nb;
397
398      nb = ntohs(((struct ip *) tunbuff)->ip_len);
399      nw = write(tun_out, tunbuff, nb);
400      if (nw != nb)
401        if (nw == -1)
402	  LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
403                    strerror(errno));
404        else
405	  LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
406
407      if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
408	while ((fptr = VarPacketAliasGetFragment(tunbuff)) != NULL) {
409	  VarPacketAliasFragmentIn(tunbuff, fptr);
410	  nb = ntohs(((struct ip *) fptr)->ip_len);
411	  nw = write(tun_out, fptr, nb);
412	  if (nw != nb)
413            if (nw == -1)
414	      LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb,
415                        strerror(errno));
416            else
417	      LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
418	  free(fptr);
419	}
420      }
421    } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
422      nb = ntohs(((struct ip *) tunbuff)->ip_len);
423      fptr = malloc(nb);
424      if (fptr == NULL)
425	LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
426      else {
427	memcpy(fptr, tunbuff, nb);
428	VarPacketAliasSaveFragment(fptr);
429      }
430    }
431  } else {			/* no aliasing */
432    if (PacketCheck(tunbuff, nb, FL_IN) < 0) {
433      pfree(bp);
434      return;
435    }
436    ipInOctets += nb;
437    nw = write(tun_out, tunbuff, nb);
438    if (nw != nb)
439      if (nw == -1)
440	LogPrintf(LogERROR, "IpInput: wrote %d, got %s\n", nb, strerror(errno));
441      else
442        LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
443  }
444  pfree(bp);
445
446  RestartIdleTimer();
447}
448
449static struct mqueue IpOutputQueues[PRI_FAST + 1];
450
451void
452IpEnqueue(int pri, char *ptr, int count)
453{
454  struct mbuf *bp;
455
456  bp = mballoc(count, MB_IPQ);
457  memcpy(MBUF_CTOP(bp), ptr, count);
458  Enqueue(&IpOutputQueues[pri], bp);
459}
460
461#if 0
462int
463IsIpEnqueued()
464{
465  struct mqueue *queue;
466  int exist = 0;
467
468  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
469    if (queue->qlen > 0) {
470      exist = 1;
471      break;
472    }
473  }
474  return (exist);
475}
476#endif
477
478void
479IpStartOutput()
480{
481  struct mqueue *queue;
482  struct mbuf *bp;
483  int cnt;
484
485  if (IpcpFsm.state != ST_OPENED)
486    return;
487  for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
488    if (queue->top) {
489      bp = Dequeue(queue);
490      if (bp) {
491	cnt = plength(bp);
492	SendPppFrame(bp);
493	RestartIdleTimer();
494	ipOutOctets += cnt;
495	break;
496      }
497    }
498  }
499}
500