diff options
author | Atsushi Murai <amurai@FreeBSD.org> | 1995-01-31 06:29:58 +0000 |
---|---|---|
committer | Atsushi Murai <amurai@FreeBSD.org> | 1995-01-31 06:29:58 +0000 |
commit | af57ed9fdcc4e2a81940fc2243c0d3949fc0e00f (patch) | |
tree | c674dc91f6ea6a8b3749770577b69790f50bda5e /usr.sbin/ppp/ip.c | |
parent | 4ffc7924900b2d63759b24d8a50cba8b89eea659 (diff) | |
download | src-af57ed9fdcc4e2a81940fc2243c0d3949fc0e00f.tar.gz src-af57ed9fdcc4e2a81940fc2243c0d3949fc0e00f.zip |
Notes
Notes:
svn path=/cvs2svn/branches/R093/; revision=6059
Diffstat (limited to 'usr.sbin/ppp/ip.c')
-rw-r--r-- | usr.sbin/ppp/ip.c | 398 |
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 000000000000..23fd550808d4 --- /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--; + } +} |