summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ppp/ip.c
diff options
context:
space:
mode:
authoramurai <amurai@FreeBSD.org>1995-01-31 06:29:58 +0000
committeramurai <amurai@FreeBSD.org>1995-01-31 06:29:58 +0000
commit21ef2761fd1e5a4beb483da8bddf767d36540dce (patch)
tree3aecd1251d1647032ad1455f304eaeeaab4987d0 /usr.sbin/ppp/ip.c
parent0487956fcf018d602bfe99b0e3398c6f4d55680a (diff)
downloadFreeBSD-src-21ef2761fd1e5a4beb483da8bddf767d36540dce.zip
FreeBSD-src-21ef2761fd1e5a4beb483da8bddf767d36540dce.tar.gz
Diffstat (limited to 'usr.sbin/ppp/ip.c')
-rw-r--r--usr.sbin/ppp/ip.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/usr.sbin/ppp/ip.c b/usr.sbin/ppp/ip.c
new file mode 100644
index 0000000..23fd550
--- /dev/null
+++ b/usr.sbin/ppp/ip.c
@@ -0,0 +1,398 @@
+/*
+ * PPP IP Protocol Interface
+ *
+ * Written by Toshiharu OHNO (tony-o@iij.ad.jp)
+ *
+ * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Internet Initiative Japan. The name of the
+ * IIJ may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id:$
+ *
+ * TODO:
+ * o Return ICMP message for filterd packet
+ * and optionaly record it into log.
+ */
+#include "fsm.h"
+#include "lcpproto.h"
+#include "hdlc.h"
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include "vars.h"
+#include "filter.h"
+
+extern void SendPppFlame();
+extern int PacketCheck();
+extern void LcpClose();
+
+static struct pppTimer IdleTimer;
+
+static void IdleTimeout()
+{
+ LogPrintf(LOG_PHASE, "Idle timer expired.\n");
+ LcpClose();
+}
+
+/*
+ * Start Idle timer. If timeout is reached, we call LcpClose() to
+ * close LCP and link.
+ */
+void
+StartIdleTimer()
+{
+ if (!(mode & MODE_DEDICATED)) {
+ StopTimer(&IdleTimer);
+ IdleTimer.func = IdleTimeout;
+ IdleTimer.load = VarIdleTimeout * SECTICKS;
+ IdleTimer.state = TIMER_STOPPED;
+ StartTimer(&IdleTimer);
+ }
+}
+
+void
+StopIdleTimer()
+{
+ StopTimer(&IdleTimer);
+}
+
+/*
+ * If any IP layer traffic is detected, refresh IdleTimer.
+ */
+static void
+RestartIdleTimer()
+{
+ if (!(mode & MODE_DEDICATED)) {
+ StopTimer(&IdleTimer);
+ StartTimer(&IdleTimer);
+ ipIdleSecs = 0;
+ }
+}
+
+static u_short interactive_ports[8] = {
+ 0, 513, 0, 0, 0, 21, 0, 23,
+};
+
+#define INTERACTIVE(p) (interactive_ports[(p) & 7] == (p))
+
+static char *TcpFlags[] = {
+ "FIN", "SYN", "RST", "PSH", "ACK", "URG",
+};
+
+static char *Direction[] = { "INP", "OUT", "OUT" };
+static struct filterent *Filters[] = { ifilters, ofilters, dfilters };
+
+static int
+PortMatch(op, pport, rport)
+int op;
+u_short pport, rport;
+{
+ switch (op) {
+ case OP_EQ:
+ return(pport == rport);
+ case OP_GT:
+ return(pport > rport);
+ case OP_LT:
+ return(pport < rport);
+ default:
+ return(0);
+ }
+}
+
+/*
+ * Check a packet against with defined filters
+ */
+static int
+FilterCheck(pip, direction)
+struct ip *pip;
+int direction;
+{
+ struct filterent *fp = Filters[direction];
+ int gotinfo, cproto, estab, n;
+ struct tcphdr *th;
+ struct udphdr *uh;
+ struct icmp *ih;
+ char *ptop;
+ u_short sport, dport;
+
+ if (fp->action) {
+ cproto = gotinfo = estab = 0;
+ sport = dport = 0;
+ for (n = 0; n < MAXFILTERS; n++) {
+ if (fp->action) {
+#ifdef DEBUG
+logprintf("rule = %d\n", n);
+#endif
+ if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
+ && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
+ if (fp->proto) {
+ if (!gotinfo) {
+ ptop = (char *)pip + (pip->ip_hl << 2);
+
+ switch (pip->ip_p) {
+ case IPPROTO_ICMP:
+ cproto = P_ICMP; ih = (struct icmp *)ptop;
+ sport = ih->icmp_type; estab = 1;
+ break;
+ case IPPROTO_UDP:
+ cproto = P_UDP; uh = (struct udphdr *)ptop;
+ sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
+ estab = 1;
+ break;
+ case IPPROTO_TCP:
+ cproto = P_TCP; th = (struct tcphdr *)ptop;
+ sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
+ estab = (th->th_flags & TH_ACK);
+ break;
+ default:
+ return(A_DENY); /* We'll block unknown type of packet */
+ }
+ gotinfo = 1;
+#ifdef DEBUG
+logprintf("dir = %d, proto = %d, srcop = %d, dstop = %d, estab = %d\n",
+direction, cproto, fp->opt.srcop, fp->opt.dstop, estab);
+if (estab == 0)
+logprintf("flag = %02x, sport = %d, dport = %d\n", th->th_flags, sport, dport);
+#endif
+ }
+#ifdef DEBUG
+ logprintf("check0: rule = %d, proto = %d, sport = %d, dport = %d\n",
+ n, cproto, sport, dport);
+ logprintf("check0: action = %d\n", fp->action);
+#endif
+ if (cproto == fp->proto) {
+ if ((fp->opt.srcop == OP_NONE ||
+ PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
+ &&
+ (fp->opt.dstop == OP_NONE ||
+ PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
+ &&
+ (fp->opt.estab == 0 || estab)) {
+ return(fp->action);
+ }
+ }
+ } else {
+ /* Address is mached. Make a decision. */
+#ifdef DEBUG
+ logprintf("check1: action = %d\n", fp->action);
+#endif
+ return(fp->action);
+ }
+ }
+ }
+ fp++;
+ }
+drop:
+ return(A_DENY); /* No rule is mached. Deny this packet */
+ }
+ return(A_PERMIT); /* No rule is given. Permit this packet */
+}
+
+static void
+IcmpError(pip, code)
+struct ip *pip;
+int code;
+{
+#ifdef notdef
+ struct mbuf *bp;
+
+ if (pip->ip_p != IPPROTO_ICMP) {
+ bp = mballoc(cnt, MB_IPIN);
+ bcopy(ptr, MBUF_CTOP(bp), cnt);
+ SendPppFlame(PRI_URGENT, bp);
+ RestartIdleTimer();
+ ipOutOctets += cnt;
+ }
+#endif
+}
+
+/*
+ * For debugging aid.
+ */
+int
+PacketCheck(cp, nb, direction)
+char *cp;
+int nb;
+int direction;
+{
+ struct ip *pip;
+ struct tcphdr *th;
+ struct udphdr *uh;
+ struct icmp *icmph;
+ char *ptop;
+ int mask, len, n;
+ int logit;
+ int pri = PRI_NORMAL;
+
+ logit = (loglevel & (1 << LOG_TCPIP));
+
+ pip = (struct ip *)cp;
+
+ if (logit) logprintf("%s ", Direction[direction]);
+
+ ptop = (cp + (pip->ip_hl << 2));
+
+ switch (pip->ip_p) {
+ case IPPROTO_ICMP:
+ if (logit) {
+ icmph = (struct icmp *)ptop;
+ logprintf("ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
+ logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), icmph->icmp_type);
+ }
+ break;
+ case IPPROTO_UDP:
+ if (logit) {
+ uh = (struct udphdr *)ptop;
+ logprintf("UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
+ logprintf("%s:%d\n", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
+ }
+ break;
+ case IPPROTO_TCP:
+ th = (struct tcphdr *)ptop;
+ if (pip->ip_tos == IPTOS_LOWDELAY)
+ pri = PRI_FAST;
+ else if (pip->ip_off == 0) {
+ if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
+ pri = PRI_FAST;
+ }
+
+ if (logit) {
+ len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
+ logprintf("TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
+ logprintf("%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
+ n = 0;
+ for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
+ if (th->th_flags & mask)
+ logprintf(" %s", TcpFlags[n]);
+ n++;
+ }
+ logprintf(" seq:%x ack:%x (%d/%d)\n",
+ ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
+ if ((th->th_flags & TH_SYN) && nb > 40) {
+ u_short *sp;
+
+ ptop += 20;
+ sp = (u_short *)ptop;
+ if (ntohs(sp[0]) == 0x0204)
+ logprintf(" MSS = %d\n", ntohs(sp[1]));
+ }
+ }
+ break;
+ }
+ pri = FilterCheck(pip, direction);
+ if (pri & A_DENY) {
+#ifdef DEBUG
+ logprintf("blocked.\n");
+#endif
+ if (direction == 0) IcmpError(pip, pri);
+ return(-1);
+ } else {
+ return(pri);
+ }
+}
+
+void
+IpInput(bp)
+struct mbuf *bp; /* IN: Pointer to IP pakcet */
+{
+ u_char *cp;
+ struct mbuf *wp;
+ int nb, nw;
+ u_char tunbuff[MAX_MRU];
+
+ cp = tunbuff;
+ nb = 0;
+ for (wp = bp; wp; wp = wp->next) { /* Copy to continuois region */
+ bcopy(MBUF_CTOP(wp), cp, wp->cnt);
+ cp += wp->cnt;
+ nb += wp->cnt;
+ }
+
+ if (PacketCheck(tunbuff, nb, 0) < 0) {
+ pfree(bp);
+ return;
+ }
+
+ ipInOctets += nb;
+ /*
+ * Pass it to tunnel device
+ */
+ nw = write(tun_out, tunbuff, nb);
+ if (nw != nb)
+ fprintf(stderr, "wrote %d, got %d\r\n");
+ pfree(bp);
+
+ RestartIdleTimer();
+}
+
+void
+IpOutput(ptr, cnt)
+u_char *ptr; /* IN: Pointer to IP packet */
+int cnt; /* IN: Length of packet */
+{
+ struct mbuf *bp;
+ int pri;
+
+ if (IpcpFsm.state != ST_OPENED)
+ return;
+
+ pri = PacketCheck(ptr, cnt, 1);
+ if (pri >= 0) {
+ bp = mballoc(cnt, MB_IPIN);
+ bcopy(ptr, MBUF_CTOP(bp), cnt);
+ SendPppFlame(pri, bp);
+ RestartIdleTimer();
+ ipOutOctets += cnt;
+ }
+}
+
+static struct mqueue IpOutputQueues[PRI_URGENT+1];
+
+void
+IpEnqueue(pri, ptr, count)
+int pri;
+char *ptr;
+int count;
+{
+ struct mbuf *bp;
+
+ bp = mballoc(count, MB_IPQ);
+ bcopy(ptr, MBUF_CTOP(bp), count);
+ Enqueue(&IpOutputQueues[pri], bp);
+}
+
+void
+IpStartOutput()
+{
+ struct mqueue *queue;
+ struct mbuf *bp;
+ int pri, cnt;
+
+ if (IpcpFsm.state != ST_OPENED)
+ return;
+ pri = PRI_URGENT;
+ for (queue = &IpOutputQueues[PRI_URGENT]; queue >= IpOutputQueues; queue--) {
+ if (queue->top) {
+ bp = Dequeue(queue);
+ if (bp) {
+ cnt = plength(bp);
+ SendPppFlame(pri, bp);
+ RestartIdleTimer();
+ ipOutOctets += cnt;
+ }
+ }
+ pri--;
+ }
+}
OpenPOWER on IntegriCloud