From 50b1cb4247102023b3d4274ecdef33ecc5ecf92d Mon Sep 17 00:00:00 2001 From: Esben Norby Date: Thu, 1 Jun 2006 14:12:21 +0000 Subject: Welcome dvmrpd started by Esben Norby some time ago by using the imsg/three process framework of ospfd. Right now it is not particularly useful, major parts are still missing but is imported to allow more people to work on it. Status: The IGMP part is mostly complete, allowing clients to join and leave groups. Election the IGMP querier of a network is also functional, only thing missing is some corner cases when going from non-querier to querier. About half of the DVMRP is functional, probes and route reports are functional. Multicast streams can be detected and the MFC can be manipulated. The RIB is not complete but operational. Not yet connected to the builds. OK claudio@ --- usr.sbin/dvmrpd/packet.c | 288 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) create mode 100644 usr.sbin/dvmrpd/packet.c (limited to 'usr.sbin/dvmrpd/packet.c') diff --git a/usr.sbin/dvmrpd/packet.c b/usr.sbin/dvmrpd/packet.c new file mode 100644 index 00000000000..f81a1614308 --- /dev/null +++ b/usr.sbin/dvmrpd/packet.c @@ -0,0 +1,288 @@ +/* $OpenBSD: packet.c,v 1.1 2006/06/01 14:12:20 norby Exp $ */ + +/* + * Copyright (c) 2004, 2005, 2006 Esben Norby + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "igmp.h" +#include "dvmrpd.h" +#include "dvmrp.h" +#include "log.h" +#include "dvmrpe.h" + +int ip_hdr_sanity_check(const struct ip *, u_int16_t); +int dvmrp_hdr_sanity_check(const struct ip *, struct dvmrp_hdr *, + u_int16_t, const struct iface *); +struct iface *find_iface(struct dvmrpd_conf *, struct in_addr); + +extern struct dvmrpd_conf *deconf; + +int +gen_dvmrp_hdr(struct buf *buf, struct iface *iface, u_int8_t code) +{ + struct dvmrp_hdr dvmrp_hdr; + + bzero(&dvmrp_hdr, sizeof(dvmrp_hdr)); + dvmrp_hdr.type = PKT_TYPE_DVMRP; + dvmrp_hdr.code = code; + dvmrp_hdr.chksum = 0; /* updated later */ + dvmrp_hdr.capabilities = DVMRP_CAP_DEFAULT; /* XXX update */ + dvmrp_hdr.minor_version = DVMRP_MINOR_VERSION; + dvmrp_hdr.major_version = DVMRP_MAJOR_VERSION; + + return (buf_add(buf, &dvmrp_hdr, sizeof(dvmrp_hdr))); +} + +/* send and receive packets */ +int +send_packet(struct iface *iface, void *pkt, size_t len, struct sockaddr_in *dst) +{ + if (iface->passive) { + log_warnx("send_packet: cannot send packet on passive " + "interface %s", iface->name); + return (-1); + } + + /* set outgoing interface for multicast traffic */ + if (IN_MULTICAST(ntohl(dst->sin_addr.s_addr))) + if (if_set_mcast(iface) == -1) { + log_warn("send_packet: error setting multicast " + "interface, %s", iface->name); + return (-1); + } + + if (sendto(iface->fd, pkt, len, 0, + (struct sockaddr *)dst, sizeof(*dst)) == -1 ) { + log_warn("send_packet: error sending packet on interface %s", + iface->name); + return (-1); + } + + return (0); +} + +void +recv_packet(int fd, short event, void *bula) +{ + struct dvmrpd_conf *xconf = bula; + struct ip ip_hdr; + struct dvmrp_hdr *dvmrp_hdr; + struct iface *iface; + struct nbr *nbr = NULL; + struct in_addr addr; + char *buf; + ssize_t r; + u_int16_t len; + int l; + + if (event != EV_READ) + return; + + /* setup buffer */ + buf = pkt_ptr; + + if ((r = recvfrom(fd, buf, READ_BUF_SIZE, 0, NULL, NULL)) == -1) { + if (errno != EAGAIN && errno != EINTR) + log_debug("recv_packet: error receiving packet"); + return; + } + + len = (u_int16_t)r; + + /* IP header sanity checks */ + if (len < sizeof(ip_hdr)) { + log_warnx("recv_packet: bad packet size"); + return; + } + + memcpy(&ip_hdr, buf, sizeof(ip_hdr)); + if ((l = ip_hdr_sanity_check(&ip_hdr, len)) == -1) + return; + buf += l; + len -= l; + + /* find a matching interface */ + if ((iface = find_iface(xconf, ip_hdr.ip_src)) == NULL) { + log_debug("recv_packet: cannot find valid interface, ip src %s", + inet_ntoa(ip_hdr.ip_src)); + return; + } + + /* header sanity checks */ + if (len < sizeof(*dvmrp_hdr)) { + log_warnx("recv_packet: bad packet size"); + return; + } + dvmrp_hdr = (struct dvmrp_hdr *)buf; + + switch (dvmrp_hdr->type) { + /* DVMRP */ + case PKT_TYPE_DVMRP: + if ((l = dvmrp_hdr_sanity_check(&ip_hdr, dvmrp_hdr, len, + iface)) == -1) + return; + + /* + * mrouted compat + * + * Old mrouted versions, send route reports before establishing + * 2-WAY neighbor relationships. + */ + if ((nbr_find_ip(iface, ip_hdr.ip_src.s_addr) == NULL) && + (dvmrp_hdr->code == DVMRP_CODE_REPORT)) { + log_debug("recv_packet: route report from neighbor" + " ID %s, compat", inet_ntoa(ip_hdr.ip_src)); + nbr = nbr_new(ip_hdr.ip_src.s_addr, iface, 0); + nbr_fsm(nbr, NBR_EVT_PROBE_RCVD); + nbr->compat = 1; + nbr->addr = ip_hdr.ip_src; + } + + if ((dvmrp_hdr->type == PKT_TYPE_DVMRP) && + (dvmrp_hdr->code != DVMRP_CODE_PROBE)) + /* find neighbor */ + if ((nbr = nbr_find_ip(iface, ip_hdr.ip_src.s_addr)) + == NULL) { + log_debug("recv_packet: unknown neighbor ID"); + return; + } + + buf += sizeof(*dvmrp_hdr); + len = l - sizeof(*dvmrp_hdr); + + inet_aton(AllDVMRPRouters, &addr); + if ((ip_hdr.ip_dst.s_addr != addr.s_addr) && + (ip_hdr.ip_dst.s_addr != iface->addr.s_addr)) { + log_debug("recv_packet: interface %s, invalid" + " destination IP address %s", iface->name, + inet_ntoa(ip_hdr.ip_dst)); + break; + } + + switch (dvmrp_hdr->code) { + case DVMRP_CODE_PROBE: + recv_probe(iface, ip_hdr.ip_src, ip_hdr.ip_src.s_addr, + dvmrp_hdr->capabilities, buf, len); + break; + case DVMRP_CODE_REPORT: + recv_report(nbr, buf, len); + break; + case DVMRP_CODE_ASK_NBRS2: + recv_ask_nbrs2(nbr, buf,len); + break; + case DVMRP_CODE_NBRS2: + recv_nbrs2(nbr, buf,len); + break; + case DVMRP_CODE_PRUNE: + recv_prune(nbr, buf, len); + break; + case DVMRP_CODE_GRAFT: + recv_graft(nbr, buf,len); + break; + case DVMRP_CODE_GRAFT_ACK: + recv_graft_ack(nbr, buf,len); + break; + default: + log_debug("recv_packet: unknown DVMRP packet type, " + "interface %s", iface->name); + } + break; + /* IGMP */ + case PKT_TYPE_MEMBER_QUERY: + recv_igmp_query(iface, ip_hdr.ip_src, buf, len); + break; + case PKT_TYPE_MEMBER_REPORTv1: + case PKT_TYPE_MEMBER_REPORTv2: + recv_igmp_report(iface, ip_hdr.ip_src, buf, len, + dvmrp_hdr->type); + break; + case PKT_TYPE_LEAVE_GROUPv2: + recv_igmp_leave(iface, ip_hdr.ip_src, buf, len); + break; + default: + log_debug("recv_packet: unknown IGMP packet type, interface %s", + iface->name); + } +} + +int +ip_hdr_sanity_check(const struct ip *ip_hdr, u_int16_t len) +{ + if (ntohs(ip_hdr->ip_len) != len) { + log_debug("recv_packet: invalid IP packet length %u", + ntohs(ip_hdr->ip_len)); + return (-1); + } + + if (ip_hdr->ip_p != IPPROTO_IGMP) + /* this is enforced by the socket itself */ + fatalx("recv_packet: invalid IP proto"); + + return (ip_hdr->ip_hl << 2); +} + +int +dvmrp_hdr_sanity_check(const struct ip *ip_hdr, struct dvmrp_hdr *dvmrp_hdr, + u_int16_t len, const struct iface *iface) +{ + /* we only support DVMRPv3 */ + if (dvmrp_hdr->major_version != DVMRP_MAJOR_VERSION) { + log_debug("recv_packet: invalid DVMRP version"); + return (-1); + } + + /* XXX enforce minor version as well, but not yet */ + + /* XXX chksum */ + + return (len); +} + +struct iface * +find_iface(struct dvmrpd_conf *xconf, struct in_addr src) +{ + struct iface *iface = NULL; + + /* returned interface needs to be active */ + LIST_FOREACH(iface, &xconf->iface_list, entry) { + if (iface->fd > 0 && + (iface->type == IF_TYPE_POINTOPOINT) && + (iface->dst.s_addr == src.s_addr) && + !iface->passive) + return (iface); + + if (iface->fd > 0 && (iface->addr.s_addr & + iface->mask.s_addr) == (src.s_addr & + iface->mask.s_addr) && !iface->passive) + return (iface); + } + + return (NULL); +} -- cgit v1.2.3