summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ripd/message.c
diff options
context:
space:
mode:
authornorby <norby@openbsd.org>2006-10-18 16:11:58 +0000
committernorby <norby@openbsd.org>2006-10-18 16:11:58 +0000
commitc04d2e365345a9a3498e5ff71b48d86210892014 (patch)
tree3583ef4b323bb56383131da485235254a96b09fc /usr.sbin/ripd/message.c
parentcomes with lxtphy(4) (diff)
downloadwireguard-openbsd-c04d2e365345a9a3498e5ff71b48d86210892014.tar.xz
wireguard-openbsd-c04d2e365345a9a3498e5ff71b48d86210892014.zip
Welcome ripd started by Michele Marchetto some time ago by using the imsg/three process framework of ospfd. He implemented most of the daemon with a little help and guidance from Claudio and I. Currently the daemon is more or less complete, with the exception of key lifetime and rollover. Not yet connected to the builds. OK claudio@
Diffstat (limited to 'usr.sbin/ripd/message.c')
-rw-r--r--usr.sbin/ripd/message.c408
1 files changed, 408 insertions, 0 deletions
diff --git a/usr.sbin/ripd/message.c b/usr.sbin/ripd/message.c
new file mode 100644
index 00000000000..d8e1e75abbd
--- /dev/null
+++ b/usr.sbin/ripd/message.c
@@ -0,0 +1,408 @@
+/* $OpenBSD: message.c,v 1.1 2006/10/18 16:11:58 norby Exp $ */
+
+/*
+ * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
+ *
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <netinet/udp.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ripd.h"
+#include "rip.h"
+#include "ripe.h"
+#include "log.h"
+
+extern struct ripd_conf *oeconf;
+
+void delete_entry(struct rip_route *);
+
+/* timers */
+void
+report_timer(int fd, short event, void *arg)
+{
+ struct timeval tv;
+
+ ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, 0, 0, NULL, 0);
+
+ /* restart report timer */
+ timerclear(&tv);
+ tv.tv_sec = KEEPALIVE + arc4random() % OFFSET;
+ evtimer_add(&oeconf->report_timer, &tv);
+}
+
+int
+start_report_timer(void)
+{
+ struct timeval tv;
+
+ timerclear(&tv);
+ tv.tv_sec = KEEPALIVE + arc4random() % OFFSET;
+ return (evtimer_add(&oeconf->report_timer, &tv));
+}
+
+void
+add_entry(struct packet_head *r_list, struct rip_route *rr)
+{
+ struct packet_entry *re;
+
+ if (rr == NULL)
+ fatalx("add_entry: no route report");
+
+ if ((re = calloc(1, sizeof(*re))) == NULL)
+ fatal("add_response");
+
+ TAILQ_INSERT_TAIL(r_list, re, entry);
+ re->rr = rr;
+ rr->refcount++;
+}
+
+void
+delete_entry(struct rip_route *rr)
+{
+ if (--rr->refcount == 0)
+ free(rr);
+}
+
+int
+send_triggered_update(struct iface *iface, struct rip_route *rr)
+{
+ struct sockaddr_in dst;
+ struct buf *buf;
+ u_int16_t afi, route_tag;
+ u_int32_t address, netmask, nexthop, metric;
+
+ inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
+
+ dst.sin_port = htons(RIP_PORT);
+ dst.sin_family = AF_INET;
+ dst.sin_len = sizeof(struct sockaddr_in);
+
+ if (iface->passive)
+ return (0);
+
+ if ((buf = buf_open(iface->mtu - sizeof(struct ip)
+ - sizeof(struct udphdr))) == NULL)
+ fatal("send_triggered_update");
+
+ gen_rip_hdr(buf, COMMAND_RESPONSE);
+
+ afi = htons(AF_INET);
+ route_tag = 0;
+
+ address = rr->address.s_addr;
+ netmask = rr->mask.s_addr;
+ nexthop = rr->nexthop.s_addr;
+ metric = htonl(rr->metric);
+
+ buf_add(buf, &afi, sizeof(afi));
+ buf_add(buf, &route_tag, sizeof(route_tag));
+ buf_add(buf, &address, sizeof(address));
+ buf_add(buf, &netmask, sizeof(netmask));
+ buf_add(buf, &nexthop, sizeof(nexthop));
+ buf_add(buf, &metric, sizeof(metric));
+
+ send_packet(iface, buf->buf, buf->wpos, &dst);
+ buf_free(buf);
+
+ return (0);
+}
+
+int
+send_request(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
+{
+ struct buf *buf;
+ struct iface *iface;
+ struct packet_entry *entry;
+ struct sockaddr_in dst;
+ u_int8_t nentries;
+ u_int8_t single_entry = 0;
+ u_int32_t address, netmask, nexthop;
+ u_int16_t port, afi, route_tag;
+ u_int32_t metric;
+
+ if (i == NULL) {
+ /* directly to a nbr */
+ iface = nbr->iface;
+ dst.sin_addr = nbr->addr;
+ port = htons(nbr->port);
+ } else {
+ /* multicast on interface */
+ iface = i;
+ inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
+ port = htons(RIP_PORT);
+ }
+
+ dst.sin_port = port;
+ dst.sin_family = AF_INET;
+ dst.sin_len = sizeof(struct sockaddr_in);
+
+ if (iface->passive)
+ return (0);
+
+ while (!TAILQ_EMPTY(r_list)) {
+ if ((buf = buf_open(iface->mtu - sizeof(struct ip)
+ - sizeof(struct udphdr))) == NULL)
+ fatal("send_request");
+
+ gen_rip_hdr(buf, COMMAND_REQUEST);
+
+ route_tag = 0;
+ nentries = 0;
+
+ if (TAILQ_FIRST(r_list) == TAILQ_LAST(r_list, packet_head))
+ single_entry = 1;
+ while (((entry = TAILQ_FIRST(r_list)) != NULL) &&
+ nentries < 25) {
+ afi = htons(AF_INET);
+
+ address = entry->rr->address.s_addr;
+ netmask = entry->rr->mask.s_addr;
+ nexthop = entry->rr->nexthop.s_addr;
+ metric = htonl(entry->rr->metric);
+
+ if (metric == htonl(INFINITY) && single_entry)
+ afi = AF_UNSPEC;
+
+ buf_add(buf, &afi, sizeof(afi));
+ buf_add(buf, &route_tag, sizeof(route_tag));
+ buf_add(buf, &address, sizeof(address));
+ buf_add(buf, &netmask, sizeof(netmask));
+ buf_add(buf, &nexthop, sizeof(nexthop));
+ buf_add(buf, &metric, sizeof(metric));
+
+ TAILQ_REMOVE(r_list, entry, entry);
+ delete_entry(entry->rr);
+ free(entry);
+ nentries++;
+ }
+ send_packet(iface, buf->buf, buf->wpos, &dst);
+ buf_free(buf);
+ }
+
+ return (0);
+}
+
+int
+send_response(struct packet_head *r_list, struct iface *i, struct nbr *nbr)
+{
+ struct buf *buf;
+ struct iface *iface;
+ struct packet_entry *entry;
+ struct sockaddr_in dst;
+ u_int8_t nentries;
+ u_int16_t port, afi, route_tag;
+ u_int32_t address, netmask, nexthop;
+ u_int32_t metric;
+
+ if (i == NULL) {
+ /* directly to a nbr */
+ iface = nbr->iface;
+ dst.sin_addr = nbr->addr;
+ port = htons(nbr->port);
+ } else {
+ /* multicast on interface */
+ iface = i;
+ inet_aton(ALL_RIP_ROUTERS, &dst.sin_addr);
+ port = htons(RIP_PORT);
+ }
+
+ dst.sin_port = port;
+ dst.sin_family = AF_INET;
+ dst.sin_len = sizeof(struct sockaddr_in);
+
+ if (iface->passive)
+ return (0);
+
+ while (!TAILQ_EMPTY(r_list)) {
+ if ((buf = buf_open(iface->mtu - sizeof(struct ip)
+ - sizeof(struct udphdr))) == NULL)
+ fatal("send_response");
+
+ gen_rip_hdr(buf, COMMAND_RESPONSE);
+
+ afi = htons(AF_INET);
+ route_tag = 0;
+ nentries = 0;
+
+ if (iface->auth_type != AUTH_NONE) {
+ if (auth_gen(buf, iface) < 0)
+ return (-1);
+ nentries++;
+ }
+
+ while ((entry = TAILQ_FIRST(r_list)) != NULL &&
+ nentries < 25) {
+ address = entry->rr->address.s_addr;
+ netmask = entry->rr->mask.s_addr;
+ nexthop = entry->rr->nexthop.s_addr;
+ metric = htonl(entry->rr->metric);
+
+ if (entry->rr->ifindex == iface->ifindex) {
+ if (oeconf->options & OPT_SPLIT_HORIZON)
+ goto free;
+ else if (oeconf->options & OPT_SPLIT_POISONED)
+ metric = htonl(INFINITY);
+ }
+
+ buf_add(buf, &afi, sizeof(afi));
+ buf_add(buf, &route_tag, sizeof(route_tag));
+ buf_add(buf, &address, sizeof(address));
+ buf_add(buf, &netmask, sizeof(netmask));
+ buf_add(buf, &nexthop, sizeof(nexthop));
+ buf_add(buf, &metric, sizeof(metric));
+free:
+ TAILQ_REMOVE(r_list, entry, entry);
+ delete_entry(entry->rr);
+ free(entry);
+ nentries++;
+ }
+
+ if (iface->auth_type == AUTH_CRYPT)
+ auth_add_trailer(buf, iface);
+
+ send_packet(iface, buf->buf, buf->wpos, &dst);
+ buf_free(buf);
+ }
+
+ return (0);
+}
+
+void
+recv_request(struct iface *i, struct nbr *nbr, char *buf, u_int16_t len)
+{
+ struct rip_entry *e;
+ struct rip_route rr;
+ int l = len;
+
+ bzero(&rr, sizeof(rr));
+
+ if (len < RIP_ENTRY_LEN) {
+ log_debug("recv_request: bad packet size, interface %s",
+ i->name);
+ return;
+ }
+
+ /*
+ * XXX is it guaranteed that bus is properly aligned.
+ * If not this will bomb on strict aligenment archs.
+ * */
+ e = (struct rip_entry *)buf;
+
+ if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
+ log_debug("recv_request: packet too long\n");
+ return;
+ }
+
+ l -= RIP_ENTRY_LEN;
+
+ /*
+ * If there is exactly one entry in the request, and it has
+ * an address family identifier of zero and a metric of
+ * infinity (i.e., 16), then this is a request to send the
+ * entire routing table.
+ */
+ if (e->AFI == 0 && e->metric == ntohl(INFINITY) && l == 0) {
+ ripe_imsg_compose_rde(IMSG_FULL_RESPONSE, nbr->peerid,
+ 0, NULL, 0);
+ return;
+ }
+
+ for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
+ if (e->AFI != AF_INET) {
+ log_debug("recv_request: AFI %d not supported\n",
+ e->AFI);
+ return;
+ }
+ rr.address.s_addr = e->address;
+ rr.mask.s_addr = e->mask;
+ rr.nexthop.s_addr = e->nexthop;
+ rr.metric = e->metric;
+ rr.ifindex = i->ifindex;
+
+ ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST, nbr->peerid,
+ 0, (void *)&rr, sizeof(rr));
+
+ e++;
+ }
+
+ ripe_imsg_compose_rde(IMSG_ROUTE_REQUEST_END, nbr->peerid,
+ 0, NULL, 0);
+}
+
+void
+recv_response(struct iface *i, struct nbr *nbr, char *buf, u_int16_t len)
+{
+ struct rip_route r;
+ struct rip_entry *e;
+ int l;
+
+ if (len < RIP_ENTRY_LEN) {
+ log_debug("recv_response: bad packet size, interface %s",
+ i->name);
+ return;
+ }
+
+ /* We must double check the length, because the only entry
+ * can be stripped off by authentication code
+ */
+ if (len < RIP_ENTRY_LEN) {
+ /* If there are no entries, our work is finished here */
+ return;
+ }
+
+ /* XXX again */
+ e = (struct rip_entry *)buf;
+
+ if (len > RIP_ENTRY_LEN * MAX_RIP_ENTRIES) {
+ log_debug("recv_response: packet too long\n");
+ return;
+ }
+
+ l = len - sizeof(*e);
+
+ for ( ; l >= 0; l -= RIP_ENTRY_LEN) {
+ if (ntohs(e->AFI) != AF_INET) {
+ log_debug("recv_response: AFI %d not supported\n",
+ e->AFI);
+ return;
+ }
+
+ r.address.s_addr = e->address;
+ r.mask.s_addr = e->mask;
+
+ if (e->nexthop == INADDR_ANY ||
+ ((i->addr.s_addr & i->mask.s_addr) !=
+ (e->nexthop & i->mask.s_addr)))
+ r.nexthop.s_addr = nbr->addr.s_addr;
+ else
+ r.nexthop.s_addr = e->nexthop;
+
+ r.metric = ntohl(e->metric);
+ r.ifindex = i->ifindex;
+
+ ripe_imsg_compose_rde(IMSG_ROUTE_FEED, 0, 0, (void *)&r,
+ sizeof(*e));
+
+ e++;
+ }
+}