ip.c revision 46828
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.59 1999/05/08 11:06:42 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#if defined(__OpenBSD__) || defined(__NetBSD__)
28#include <sys/socket.h>
29#endif
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 <sys/un.h>
38
39#include <errno.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <termios.h>
44#include <unistd.h>
45
46#include "layer.h"
47#include "proto.h"
48#include "mbuf.h"
49#include "log.h"
50#include "defs.h"
51#include "timer.h"
52#include "fsm.h"
53#include "lqr.h"
54#include "hdlc.h"
55#include "throughput.h"
56#include "iplist.h"
57#include "slcompress.h"
58#include "ipcp.h"
59#include "filter.h"
60#include "descriptor.h"
61#include "lcp.h"
62#include "ccp.h"
63#include "link.h"
64#include "mp.h"
65#ifndef NORADIUS
66#include "radius.h"
67#endif
68#include "bundle.h"
69#include "vjcomp.h"
70#include "tun.h"
71#include "ip.h"
72
73static const u_short interactive_ports[32] = {
74  544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
75  80, 81, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
76};
77
78#define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
79
80static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
81
82static int
83PortMatch(int op, u_short pport, u_short rport)
84{
85  switch (op) {
86    case OP_EQ:
87    return (pport == rport);
88  case OP_GT:
89    return (pport > rport);
90  case OP_LT:
91    return (pport < rport);
92  default:
93    return (0);
94  }
95}
96
97/*
98 *  Check a packet against a defined filter
99 */
100static int
101FilterCheck(struct ip *pip, struct filter *filter)
102{
103  int gotinfo, cproto, estab, syn, finrst, n, len, didname;
104  struct tcphdr *th;
105  struct udphdr *uh;
106  struct icmp *ih;
107  char *ptop;
108  u_short sport, dport;
109  struct filterent *fp = filter->rule;
110  char dbuff[100];
111
112  if (fp->action) {
113    cproto = gotinfo = estab = syn = finrst = didname = 0;
114    sport = dport = 0;
115    for (n = 0; n < MAXFILTERS; n++) {
116      if (fp->action) {
117	/* permit fragments on in and out filter */
118        if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0)
119	  return (A_PERMIT);
120
121        if (!didname)
122          log_Printf(LogDEBUG, "%s filter:\n", filter->name);
123        didname = 1;
124
125	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
126	    (fp->saddr.s_addr & fp->smask.s_addr) &&
127	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
128	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
129	  if (fp->proto) {
130	    if (!gotinfo) {
131	      ptop = (char *) pip + (pip->ip_hl << 2);
132
133	      switch (pip->ip_p) {
134	      case IPPROTO_ICMP:
135		cproto = P_ICMP;
136		ih = (struct icmp *) ptop;
137		sport = ih->icmp_type;
138		estab = syn = finrst = -1;
139                if (log_IsKept(LogDEBUG))
140		  snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
141		break;
142	      case IPPROTO_UDP:
143	      case IPPROTO_IGMP:
144	      case IPPROTO_IPIP:
145		cproto = P_UDP;
146		uh = (struct udphdr *) ptop;
147		sport = ntohs(uh->uh_sport);
148		dport = ntohs(uh->uh_dport);
149		estab = syn = finrst = -1;
150                if (log_IsKept(LogDEBUG))
151		  snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
152                           sport, dport);
153		break;
154	      case IPPROTO_TCP:
155		cproto = P_TCP;
156		th = (struct tcphdr *) ptop;
157		sport = ntohs(th->th_sport);
158		dport = ntohs(th->th_dport);
159		estab = (th->th_flags & TH_ACK);
160		syn = (th->th_flags & TH_SYN);
161		finrst = (th->th_flags & (TH_FIN|TH_RST));
162                if (log_IsKept(LogDEBUG)) {
163                  if (!estab)
164		    snprintf(dbuff, sizeof dbuff,
165                             "flags = %02x, sport = %d, dport = %d",
166                             th->th_flags, sport, dport);
167                  else
168                    *dbuff = '\0';
169                }
170		break;
171	      default:
172		return (A_DENY);       /* We'll block unknown type of packet */
173	      }
174              if (log_IsKept(LogDEBUG)) {
175                if (estab != -1) {
176                  len = strlen(dbuff);
177                  snprintf(dbuff + len, sizeof dbuff - len,
178                           ", estab = %d, syn = %d, finrst = %d",
179                           estab, syn, finrst);
180                }
181	        log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
182                          filter_Proto2Nam(cproto), dbuff);
183              }
184	      gotinfo = 1;
185	    }
186            if (log_IsKept(LogDEBUG)) {
187	      if (fp->opt.srcop != OP_NONE) {
188                snprintf(dbuff, sizeof dbuff, ", src %s %d",
189                         filter_Op2Nam(fp->opt.srcop), fp->opt.srcport);
190                len = strlen(dbuff);
191              } else
192                len = 0;
193	      if (fp->opt.dstop != OP_NONE) {
194                snprintf(dbuff + len, sizeof dbuff - len,
195                         ", dst %s %d", filter_Op2Nam(fp->opt.dstop),
196                         fp->opt.dstport);
197              } else if (!len)
198                *dbuff = '\0';
199
200	      log_Printf(LogDEBUG, "  rule = %d: Address match, "
201                        "check against proto %s%s, action = %s\n",
202                        n, filter_Proto2Nam(fp->proto),
203                        dbuff, filter_Action2Nam(fp->action));
204            }
205
206	    if (cproto == fp->proto) {
207	      if ((fp->opt.srcop == OP_NONE ||
208		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) &&
209		  (fp->opt.dstop == OP_NONE ||
210		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) &&
211		  (fp->opt.estab == 0 || estab) &&
212		  (fp->opt.syn == 0 || syn) &&
213		  (fp->opt.finrst == 0 || finrst)) {
214		return (fp->action);
215	      }
216	    }
217	  } else {
218	    /* Address is mached. Make a decision. */
219	    log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
220                      filter_Action2Nam(fp->action));
221	    return (fp->action);
222	  }
223	} else
224	  log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
225      }
226      fp++;
227    }
228    return (A_DENY);		/* No rule is mached. Deny this packet */
229  }
230  return (A_PERMIT);		/* No rule is given. Permit this packet */
231}
232
233#ifdef notdef
234static void
235IcmpError(struct ip *pip, int code)
236{
237  struct mbuf *bp;
238
239  if (pip->ip_p != IPPROTO_ICMP) {
240    bp = mbuf_Alloc(cnt, MB_IPIN);
241    memcpy(MBUF_CTOP(bp), ptr, cnt);
242    vj_SendFrame(bp);
243    ipcp_AddOutOctets(cnt);
244  }
245}
246#endif
247
248/*
249 *  For debugging aid.
250 */
251int
252PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
253{
254  struct ip *pip;
255  struct tcphdr *th;
256  struct udphdr *uh;
257  struct icmp *icmph;
258  char *ptop;
259  int mask, len, n;
260  int pri = PRI_NORMAL;
261  int logit, loglen;
262  char logbuf[200];
263
264  logit = log_IsKept(LogTCPIP) && filter->logok;
265  loglen = 0;
266
267  pip = (struct ip *) cp;
268
269  if (logit && loglen < sizeof logbuf) {
270    snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
271    loglen += strlen(logbuf + loglen);
272  }
273  ptop = (cp + (pip->ip_hl << 2));
274
275  switch (pip->ip_p) {
276  case IPPROTO_ICMP:
277    if (logit && loglen < sizeof logbuf) {
278      icmph = (struct icmp *) ptop;
279      snprintf(logbuf + loglen, sizeof logbuf - loglen,
280	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
281      loglen += strlen(logbuf + loglen);
282      snprintf(logbuf + loglen, sizeof logbuf - loglen,
283	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
284      loglen += strlen(logbuf + loglen);
285    }
286    break;
287  case IPPROTO_UDP:
288    if (logit && loglen < sizeof logbuf) {
289      uh = (struct udphdr *) ptop;
290      snprintf(logbuf + loglen, sizeof logbuf - loglen,
291	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
292      loglen += strlen(logbuf + loglen);
293      snprintf(logbuf + loglen, sizeof logbuf - loglen,
294	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
295      loglen += strlen(logbuf + loglen);
296    }
297    break;
298  case IPPROTO_IPIP:
299    if (logit && loglen < sizeof logbuf) {
300      uh = (struct udphdr *) ptop;
301      snprintf(logbuf + loglen, sizeof logbuf - loglen,
302	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
303      loglen += strlen(logbuf + loglen);
304      snprintf(logbuf + loglen, sizeof logbuf - loglen,
305	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
306      loglen += strlen(logbuf + loglen);
307    }
308    break;
309  case IPPROTO_IGMP:
310    if (logit && loglen < sizeof logbuf) {
311      uh = (struct udphdr *) ptop;
312      snprintf(logbuf + loglen, sizeof logbuf - loglen,
313	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
314      loglen += strlen(logbuf + loglen);
315      snprintf(logbuf + loglen, sizeof logbuf - loglen,
316	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
317      loglen += strlen(logbuf + loglen);
318    }
319    break;
320  case IPPROTO_TCP:
321    th = (struct tcphdr *) ptop;
322    if (pip->ip_tos == IPTOS_LOWDELAY)
323      pri = PRI_FAST;
324    else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
325      if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
326	pri = PRI_FAST;
327    }
328    if (logit && loglen < sizeof logbuf) {
329      len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
330      snprintf(logbuf + loglen, sizeof logbuf - loglen,
331	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
332      loglen += strlen(logbuf + loglen);
333      snprintf(logbuf + loglen, sizeof logbuf - loglen,
334	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
335      loglen += strlen(logbuf + loglen);
336      n = 0;
337      for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
338	if (th->th_flags & mask) {
339	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
340	  loglen += strlen(logbuf + loglen);
341	}
342	n++;
343      }
344      snprintf(logbuf + loglen, sizeof logbuf - loglen,
345	       "  seq:%lx  ack:%lx (%d/%d)",
346	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
347      loglen += strlen(logbuf + loglen);
348      if ((th->th_flags & TH_SYN) && nb > 40) {
349	u_short *sp;
350
351	ptop += 20;
352	sp = (u_short *) ptop;
353	if (ntohs(sp[0]) == 0x0204) {
354	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
355		   " MSS = %d", ntohs(sp[1]));
356	  loglen += strlen(logbuf + loglen);
357	}
358      }
359    }
360    break;
361  }
362
363  if ((FilterCheck(pip, filter) & A_DENY)) {
364    if (logit)
365      log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
366#ifdef notdef
367    if (direction == 0)
368      IcmpError(pip, pri);
369#endif
370    return (-1);
371  } else {
372    /* Check Keep Alive filter */
373    if (logit) {
374      if (FilterCheck(pip, &bundle->filter.alive) & A_DENY)
375        log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
376      else
377        log_Printf(LogTCPIP, "%s\n", logbuf);
378    }
379    return (pri);
380  }
381}
382
383struct mbuf *
384ip_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
385{
386  int nb, nw;
387  struct tun_data tun;
388  struct ip *pip;
389
390  if (bundle->ncp.ipcp.fsm.state != ST_OPENED) {
391    log_Printf(LogWARN, "ip_Input: IPCP not open - packet dropped\n");
392    mbuf_Free(bp);
393    return NULL;
394  }
395
396  tun_fill_header(tun, AF_INET);
397  nb = mbuf_Length(bp);
398  mbuf_Read(bp, tun.data, nb);
399
400  if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0)
401    return NULL;
402
403  pip = (struct ip *)tun.data;
404  if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
405    bundle_StartIdleTimer(bundle);
406
407  ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
408
409  nb += sizeof tun - sizeof tun.data;
410  nw = write(bundle->dev.fd, &tun, nb);
411  if (nw != nb) {
412    if (nw == -1)
413      log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno));
414    else
415      log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
416  }
417
418  return NULL;
419}
420
421void
422ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
423{
424  struct mbuf *bp;
425
426  if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0])
427    log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
428  else {
429    /*
430     * We allocate an extra 6 bytes, four at the front and two at the end.
431     * This is an optimisation so that we need to do less work in
432     * mbuf_Prepend() in acf_LayerPush() and proto_LayerPush() and
433     * appending in hdlc_LayerPush().
434     */
435    bp = mbuf_Alloc(count + 6, MB_IPQ);
436    bp->offset += 4;
437    bp->cnt -= 6;
438    memcpy(MBUF_CTOP(bp), ptr, count);
439    mbuf_Enqueue(&ipcp->Queue[pri], bp);
440  }
441}
442
443void
444ip_DeleteQueue(struct ipcp *ipcp)
445{
446  struct mqueue *queue;
447
448  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
449    while (queue->top)
450      mbuf_Free(mbuf_Dequeue(queue));
451}
452
453int
454ip_QueueLen(struct ipcp *ipcp)
455{
456  struct mqueue *queue;
457  int result = 0;
458
459  for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
460    result += queue->qlen;
461
462  return result;
463}
464
465int
466ip_PushPacket(struct link *l, struct bundle *bundle)
467{
468  struct ipcp *ipcp = &bundle->ncp.ipcp;
469  struct mqueue *queue;
470  struct mbuf *bp;
471  struct ip *pip;
472  int cnt;
473
474  if (ipcp->fsm.state != ST_OPENED)
475    return 0;
476
477  for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--)
478    if (queue->top) {
479      bp = mbuf_Contiguous(mbuf_Dequeue(queue));
480      cnt = mbuf_Length(bp);
481      pip = (struct ip *)MBUF_CTOP(bp);
482      if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
483        bundle_StartIdleTimer(bundle);
484      link_PushPacket(l, bp, bundle, PRI_NORMAL, PROTO_IP);
485      ipcp_AddOutOctets(ipcp, cnt);
486      return 1;
487    }
488
489  return 0;
490}
491