summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2006-11-17 08:55:32 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2006-11-17 08:55:32 +0000
commitaa748b97fe57f4635f47ab0336b87da3cb55858c (patch)
tree743416ed5e159cd87cda9bea1f0e9405f2a2f539 /usr.sbin
parent78604d2745675cfadeb29e2681177ec9ec7a86b5 (diff)
Support for multiple networks on one interface. Until now only the main
address of a interface could be used. Now it is possible to specify a interface more than once if multiple networks are configured. An alternative network can be specified via e.g. interface em0:10.0.5.1. The old interface syntax without the IP still works and uses the main/first configured IP address. ospfd now needs to include the IP header on outgoing messages as it is not possible to specifiy the source address in sendto(2). Additionally all multicast joins and leaves have to be tracked. OK norby@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/ospfd/interface.c159
-rw-r--r--usr.sbin/ospfd/kroute.c124
-rw-r--r--usr.sbin/ospfd/ospfd.h11
-rw-r--r--usr.sbin/ospfd/ospfe.c11
-rw-r--r--usr.sbin/ospfd/ospfe.h7
-rw-r--r--usr.sbin/ospfd/packet.c39
-rw-r--r--usr.sbin/ospfd/parse.y41
7 files changed, 253 insertions, 139 deletions
diff --git a/usr.sbin/ospfd/interface.c b/usr.sbin/ospfd/interface.c
index 112f022e37e..f2e952e137a 100644
--- a/usr.sbin/ospfd/interface.c
+++ b/usr.sbin/ospfd/interface.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: interface.c,v 1.53 2006/09/27 14:37:38 claudio Exp $ */
+/* $OpenBSD: interface.c,v 1.54 2006/11/17 08:55:31 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -148,12 +148,9 @@ if_fsm(struct iface *iface, enum iface_event event)
}
struct iface *
-if_new(struct kif *kif)
+if_new(struct kif *kif, struct kif_addr *ka)
{
- struct sockaddr_in *sain;
struct iface *iface;
- struct ifreq *ifr;
- int s;
if ((iface = calloc(1, sizeof(*iface))) == NULL)
err(1, "if_new: calloc");
@@ -177,14 +174,6 @@ if_new(struct kif *kif)
strlcpy(iface->name, kif->ifname, sizeof(iface->name));
- if ((ifr = calloc(1, sizeof(*ifr))) == NULL)
- err(1, "if_new: calloc");
-
- /* set up ifreq */
- strlcpy(ifr->ifr_name, kif->ifname, sizeof(ifr->ifr_name));
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
- err(1, "if_new: socket");
-
/* get type */
if (kif->flags & IFF_POINTOPOINT)
iface->type = IF_TYPE_POINTOPOINT;
@@ -203,29 +192,13 @@ if_new(struct kif *kif)
iface->linkstate = kif->link_state;
iface->media_type = kif->media_type;
- /* get address */
- if (ioctl(s, SIOCGIFADDR, ifr) < 0)
- err(1, "if_new: cannot get address");
- sain = (struct sockaddr_in *)&ifr->ifr_addr;
- iface->addr = sain->sin_addr;
-
- /* get mask */
- if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
- err(1, "if_new: cannot get mask");
- sain = (struct sockaddr_in *)&ifr->ifr_addr;
- iface->mask = sain->sin_addr;
-
- /* get p2p dst address */
+ /* set address, mask and p2p addr */
+ iface->addr = ka->addr;
+ iface->mask = ka->mask;
if (kif->flags & IFF_POINTOPOINT) {
- if (ioctl(s, SIOCGIFDSTADDR, ifr) < 0)
- err(1, "if_new: cannot get dst addr");
- sain = (struct sockaddr_in *)&ifr->ifr_addr;
- iface->dst = sain->sin_addr;
+ iface->dst = ka->dstbrd;
}
- free(ifr);
- close(s);
-
return (iface);
}
@@ -355,11 +328,8 @@ if_act_start(struct iface *iface)
switch (iface->type) {
case IF_TYPE_POINTOPOINT:
inet_aton(AllSPFRouters, &addr);
- if (if_join_group(iface, &addr)) {
- log_warnx("if_act_start: error joining group %s, "
- "interface %s", inet_ntoa(addr), iface->name);
+ if (if_join_group(iface, &addr))
return (-1);
- }
iface->state = IF_STA_POINTTOPOINT;
break;
case IF_TYPE_VIRTUALLINK:
@@ -372,11 +342,8 @@ if_act_start(struct iface *iface)
return (-1);
case IF_TYPE_BROADCAST:
inet_aton(AllSPFRouters, &addr);
- if (if_join_group(iface, &addr)) {
- log_warnx("if_act_start: error joining group %s, "
- "interface %s", inet_ntoa(addr), iface->name);
+ if (if_join_group(iface, &addr))
return (-1);
- }
if (iface->priority == 0) {
iface->state = IF_STA_DROTHER;
} else {
@@ -513,20 +480,12 @@ start:
inet_aton(AllDRouters, &addr);
if (old_state & IF_STA_DRORBDR &&
(iface->state & IF_STA_DRORBDR) == 0) {
- if (if_leave_group(iface, &addr)) {
- log_warnx("if_act_elect: "
- "error leaving group %s, interface %s",
- inet_ntoa(addr), iface->name);
+ if (if_leave_group(iface, &addr))
return (-1);
- }
} else if ((old_state & IF_STA_DRORBDR) == 0 &&
iface->state & IF_STA_DRORBDR) {
- if (if_join_group(iface, &addr)) {
- log_warnx("if_act_elect: "
- "error joining group %s, interface %s",
- inet_ntoa(addr), iface->name);
+ if (if_join_group(iface, &addr))
return (-1);
- }
}
LIST_FOREACH(nbr, &iface->nbr_list, entry) {
@@ -674,31 +633,6 @@ if_to_ctl(struct iface *iface)
/* misc */
int
-if_set_mcast_ttl(int fd, u_int8_t ttl)
-{
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL,
- (char *)&ttl, sizeof(ttl)) < 0) {
- log_warn("if_set_mcast_ttl: error setting "
- "IP_MULTICAST_TTL to %d", ttl);
- return (-1);
- }
-
- return (0);
-}
-
-int
-if_set_tos(int fd, int tos)
-{
- if (setsockopt(fd, IPPROTO_IP, IP_TOS,
- (int *)&tos, sizeof(tos)) < 0) {
- log_warn("if_set_tos: error setting IP_TOS to 0x%x", tos);
- return (-1);
- }
-
- return (0);
-}
-
-int
if_set_recvif(int fd, int enable)
{
if (setsockopt(fd, IPPROTO_IP, IP_RECVIF, &enable,
@@ -720,21 +654,52 @@ if_set_recvbuf(int fd)
bsize /= 2;
}
+/*
+ * only one JOIN or DROP per interface and address is allowed so we need
+ * to keep track of what is added and removed.
+ */
+struct if_group_count {
+ LIST_ENTRY(if_group_count) entry;
+ struct in_addr addr;
+ unsigned int ifindex;
+ int count;
+};
+
+LIST_HEAD(,if_group_count) ifglist = LIST_HEAD_INITIALIZER(ifglist);
+
int
if_join_group(struct iface *iface, struct in_addr *addr)
{
- struct ip_mreq mreq;
+ struct ip_mreq mreq;
+ struct if_group_count *ifg;
switch (iface->type) {
case IF_TYPE_POINTOPOINT:
case IF_TYPE_BROADCAST:
+ LIST_FOREACH(ifg, &ifglist, entry)
+ if (iface->ifindex == ifg->ifindex &&
+ addr->s_addr == ifg->addr.s_addr)
+ break;
+ if (ifg == NULL) {
+ if ((ifg = calloc(1, sizeof(*ifg))) == NULL)
+ fatal("if_join_group");
+ ifg->addr.s_addr = addr->s_addr;
+ ifg->ifindex = iface->ifindex;
+ LIST_INSERT_HEAD(&ifglist, ifg, entry);
+ }
+
+ if (ifg->count++ != 0)
+ /* already joined */
+ return (0);
+
mreq.imr_multiaddr.s_addr = addr->s_addr;
mreq.imr_interface.s_addr = iface->addr.s_addr;
if (setsockopt(iface->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(void *)&mreq, sizeof(mreq)) < 0) {
- log_debug("if_join_group: error IP_ADD_MEMBERSHIP, "
- "interface %s", iface->name);
+ log_warn("if_join_group: error IP_ADD_MEMBERSHIP, "
+ "interface %s address %s", iface->name,
+ inet_ntoa(*addr));
return (-1);
}
break;
@@ -754,20 +719,37 @@ if_join_group(struct iface *iface, struct in_addr *addr)
int
if_leave_group(struct iface *iface, struct in_addr *addr)
{
- struct ip_mreq mreq;
+ struct ip_mreq mreq;
+ struct if_group_count *ifg;
switch (iface->type) {
case IF_TYPE_POINTOPOINT:
case IF_TYPE_BROADCAST:
+ LIST_FOREACH(ifg, &ifglist, entry)
+ if (iface->ifindex == ifg->ifindex &&
+ addr->s_addr == ifg->addr.s_addr)
+ break;
+
+ /* if interface is not found just try to drop membership */
+ if (ifg && --ifg->count != 0)
+ /* others still joined */
+ return (0);
+
mreq.imr_multiaddr.s_addr = addr->s_addr;
mreq.imr_interface.s_addr = iface->addr.s_addr;
if (setsockopt(iface->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP,
(void *)&mreq, sizeof(mreq)) < 0) {
- log_debug("if_leave_group: error IP_DROP_MEMBERSHIP, "
- "interface %s", iface->name);
+ log_warn("if_leave_group: error IP_DROP_MEMBERSHIP, "
+ "interface %s address %s", iface->name,
+ inet_ntoa(*addr));
return (-1);
}
+
+ if (ifg) {
+ LIST_REMOVE(ifg, entry);
+ free(ifg);
+ }
break;
case IF_TYPE_POINTOMULTIPOINT:
case IF_TYPE_VIRTUALLINK:
@@ -821,3 +803,16 @@ if_set_mcast_loop(int fd)
return (0);
}
+
+int
+if_set_ip_hdrincl(int fd)
+{
+ int hincl = 1;
+
+ if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl)) < 0) {
+ log_warn("if_set_ip_hdrincl: error setting IP_HDRINCL");
+ return (-1);
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/ospfd/kroute.c b/usr.sbin/ospfd/kroute.c
index f85c9b24e4f..a33f91688f1 100644
--- a/usr.sbin/ospfd/kroute.c
+++ b/usr.sbin/ospfd/kroute.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kroute.c,v 1.34 2006/11/16 15:55:29 henning Exp $ */
+/* $OpenBSD: kroute.c,v 1.35 2006/11/17 08:55:31 claudio Exp $ */
/*
* Copyright (c) 2004 Esben Norby <norby@openbsd.org>
@@ -54,6 +54,7 @@ struct kroute_node {
struct kif_node {
RB_ENTRY(kif_node) entry;
+ TAILQ_HEAD(, kif_addr) addrs;
struct kif k;
};
@@ -488,13 +489,24 @@ kif_find(int ifindex)
}
struct kif *
-kif_findname(char *ifname)
+kif_findname(char *ifname, struct in_addr addr, struct kif_addr **kap)
{
struct kif_node *kif;
+ struct kif_addr *ka;
RB_FOREACH(kif, kif_tree, &kit)
- if (!strcmp(ifname, kif->k.ifname))
+ if (!strcmp(ifname, kif->k.ifname)) {
+ ka = TAILQ_FIRST(&kif->addrs);
+ if (addr.s_addr != 0) {
+ TAILQ_FOREACH(ka, &kif->addrs, entry) {
+ if (addr.s_addr == ka->addr.s_addr)
+ break;
+ }
+ }
+ if (kap != NULL)
+ *kap = ka;
return (&kif->k);
+ }
return (NULL);
}
@@ -514,11 +526,17 @@ kif_insert(struct kif_node *kif)
int
kif_remove(struct kif_node *kif)
{
+ struct kif_addr *ka;
+
if (RB_REMOVE(kif_tree, &kit, kif) == NULL) {
log_warnx("RB_REMOVE(kif_tree, &kit, kif)");
return (-1);
}
+ while ((ka = TAILQ_FIRST(&kif->addrs)) != NULL) {
+ TAILQ_REMOVE(&kif->addrs, ka, entry);
+ free(ka);
+ }
free(kif);
return (0);
}
@@ -894,10 +912,14 @@ fetchifs(int ifindex)
size_t len;
int mib[6];
char *buf, *next, *lim;
- struct if_msghdr ifm;
- struct kif_node *kif;
+ struct rt_msghdr *rtm;
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ struct kif_node *kif = NULL;
+ struct kif_addr *kaddr;
struct sockaddr *sa, *rti_info[RTAX_MAX];
struct sockaddr_dl *sdl;
+ struct sockaddr_in *sain;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
@@ -921,32 +943,37 @@ fetchifs(int ifindex)
}
lim = buf + len;
- for (next = buf; next < lim; next += ifm.ifm_msglen) {
- memcpy(&ifm, next, sizeof(ifm));
- if (ifm.ifm_type != RTM_IFINFO)
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if (rtm->rtm_version != RTM_VERSION)
continue;
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)rtm;
+ sa = (struct sockaddr *)(next + sizeof(*ifm));
+ get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
- sa = (struct sockaddr *)(next + sizeof(ifm));
- get_rtaddrs(ifm.ifm_addrs, sa, rti_info);
-
- if ((kif = calloc(1, sizeof(struct kif_node))) == NULL) {
- log_warn("fetchifs");
- free(buf);
- return (-1);
- }
+ if ((kif = calloc(1, sizeof(struct kif_node))) ==
+ NULL) {
+ log_warn("fetchifs");
+ free(buf);
+ return (-1);
+ }
- kif->k.ifindex = ifm.ifm_index;
- kif->k.flags = ifm.ifm_flags;
- kif->k.link_state = ifm.ifm_data.ifi_link_state;
- kif->k.media_type = ifm.ifm_data.ifi_type;
- kif->k.baudrate = ifm.ifm_data.ifi_baudrate;
- kif->k.mtu = ifm.ifm_data.ifi_mtu;
- kif->k.nh_reachable = (kif->k.flags & IFF_UP) &&
- (ifm.ifm_data.ifi_link_state == LINK_STATE_UP ||
- (ifm.ifm_data.ifi_link_state == LINK_STATE_UNKNOWN &&
- ifm.ifm_data.ifi_type != IFT_CARP));
- if ((sa = rti_info[RTAX_IFP]) != NULL)
- if (sa->sa_family == AF_LINK) {
+ kif->k.ifindex = ifm->ifm_index;
+ kif->k.flags = ifm->ifm_flags;
+ kif->k.link_state = ifm->ifm_data.ifi_link_state;
+ kif->k.media_type = ifm->ifm_data.ifi_type;
+ kif->k.baudrate = ifm->ifm_data.ifi_baudrate;
+ kif->k.mtu = ifm->ifm_data.ifi_mtu;
+ kif->k.nh_reachable = (kif->k.flags & IFF_UP) &&
+ (ifm->ifm_data.ifi_link_state == LINK_STATE_UP ||
+ (ifm->ifm_data.ifi_link_state ==
+ LINK_STATE_UNKNOWN &&
+ ifm->ifm_data.ifi_type != IFT_CARP));
+ TAILQ_INIT(&kif->addrs);
+ if ((sa = rti_info[RTAX_IFP]) != NULL &&
+ sa->sa_family == AF_LINK) {
sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen >= sizeof(kif->k.ifname))
memcpy(kif->k.ifname, sdl->sdl_data,
@@ -957,7 +984,46 @@ fetchifs(int ifindex)
/* string already terminated via calloc() */
}
- kif_insert(kif);
+ kif_insert(kif);
+ break;
+ case RTM_NEWADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+ if (kif && ifam->ifam_index != kif->k.ifindex)
+ fatalx("fetchifs: bad interafce table");
+ if (kif == NULL || (ifam->ifam_addrs &
+ (RTA_NETMASK | RTA_IFA | RTA_BRD)) == 0)
+ break;
+ sa = (struct sockaddr *)(next + sizeof(*ifam));
+ get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
+
+ if ((sa = rti_info[RTAX_IFA]) != NULL &&
+ sa->sa_family == AF_INET) {
+ if ((kaddr = calloc(1,
+ sizeof(struct kif_addr))) == NULL) {
+ log_warn("fetchifs");
+ free(buf);
+ return (-1);
+ }
+
+ sain = (struct sockaddr_in *)sa;
+ kaddr->addr = sain->sin_addr;
+
+ if ((sa = rti_info[RTAX_NETMASK]) != NULL) {
+ sain = (struct sockaddr_in *)sa;
+ kaddr->mask = sain->sin_addr;
+ } else
+ kaddr->mask.s_addr = INADDR_NONE;
+
+ if ((sa = rti_info[RTAX_BRD]) != NULL) {
+ sain = (struct sockaddr_in *)sa;
+ kaddr->dstbrd = sain->sin_addr;
+ } else
+ kaddr->dstbrd.s_addr = INADDR_NONE;
+
+ TAILQ_INSERT_TAIL(&kif->addrs, kaddr, entry);
+ }
+ break;
+ }
}
free(buf);
return (0);
diff --git a/usr.sbin/ospfd/ospfd.h b/usr.sbin/ospfd/ospfd.h
index b8039d357d3..6121643ee9c 100644
--- a/usr.sbin/ospfd/ospfd.h
+++ b/usr.sbin/ospfd/ospfd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfd.h,v 1.60 2006/06/28 10:53:39 norby Exp $ */
+/* $OpenBSD: ospfd.h,v 1.61 2006/11/17 08:55:31 claudio Exp $ */
/*
* Copyright (c) 2004 Esben Norby <norby@openbsd.org>
@@ -408,6 +408,13 @@ struct kroute {
u_int8_t prefixlen;
};
+struct kif_addr {
+ TAILQ_ENTRY(kif_addr) entry;
+ struct in_addr addr;
+ struct in_addr mask;
+ struct in_addr dstbrd;
+};
+
struct kif {
char ifname[IF_NAMESIZE];
u_long baudrate;
@@ -557,7 +564,7 @@ void kr_fib_decouple(void);
void kr_dispatch_msg(int, short, void *);
void kr_show_route(struct imsg *);
void kr_ifinfo(char *, pid_t);
-struct kif *kif_findname(char *);
+struct kif *kif_findname(char *, struct in_addr, struct kif_addr **);
u_int8_t mask2prefixlen(in_addr_t);
in_addr_t prefixlen2mask(u_int8_t);
diff --git a/usr.sbin/ospfd/ospfe.c b/usr.sbin/ospfd/ospfe.c
index 59833170181..471ccf60870 100644
--- a/usr.sbin/ospfd/ospfe.c
+++ b/usr.sbin/ospfd/ospfe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfe.c,v 1.48 2006/09/27 14:37:38 claudio Exp $ */
+/* $OpenBSD: ospfe.c,v 1.49 2006/11/17 08:55:31 claudio Exp $ */
/*
* Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
@@ -97,15 +97,10 @@ ospfe(struct ospfd_conf *xconf, int pipe_parent2ospfe[2], int pipe_ospfe2rde[2],
fatal("error creating raw socket");
/* set some defaults */
- if (if_set_mcast_ttl(xconf->ospf_socket,
- IP_DEFAULT_MULTICAST_TTL) == -1)
- fatal("if_set_mcast_ttl");
-
if (if_set_mcast_loop(xconf->ospf_socket) == -1)
fatal("if_set_mcast_loop");
-
- if (if_set_tos(xconf->ospf_socket, IPTOS_PREC_INTERNETCONTROL) == -1)
- fatal("if_set_tos");
+ if (if_set_ip_hdrincl(xconf->ospf_socket) == -1)
+ fatal("if_set_ip_hdrincl");
if (if_set_recvif(xconf->ospf_socket, 1) == -1)
fatal("if_set_recvif");
if_set_recvbuf(xconf->ospf_socket);
diff --git a/usr.sbin/ospfd/ospfe.h b/usr.sbin/ospfd/ospfe.h
index 5558892696a..822b887b914 100644
--- a/usr.sbin/ospfd/ospfe.h
+++ b/usr.sbin/ospfd/ospfe.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ospfe.h,v 1.32 2006/09/27 14:37:38 claudio Exp $ */
+/* $OpenBSD: ospfe.h,v 1.33 2006/11/17 08:55:31 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -132,7 +132,7 @@ void orig_net_lsa(struct iface *);
/* interface.c */
int if_fsm(struct iface *, enum iface_event);
-struct iface *if_new(struct kif *);
+struct iface *if_new(struct kif *, struct kif_addr *);
void if_del(struct iface *);
void if_init(struct ospfd_conf *, struct iface *);
@@ -145,11 +145,10 @@ struct ctl_iface *if_to_ctl(struct iface *);
int if_join_group(struct iface *, struct in_addr *);
int if_leave_group(struct iface *, struct in_addr *);
int if_set_mcast(struct iface *);
-int if_set_mcast_ttl(int, u_int8_t);
-int if_set_tos(int, int);
int if_set_recvif(int, int);
void if_set_recvbuf(int);
int if_set_mcast_loop(int);
+int if_set_ip_hdrincl(int);
/* lsack.c */
int delay_lsa_ack(struct iface *, struct lsa_hdr *);
diff --git a/usr.sbin/ospfd/packet.c b/usr.sbin/ospfd/packet.c
index e57b28375c1..2f6ac3438b9 100644
--- a/usr.sbin/ospfd/packet.c
+++ b/usr.sbin/ospfd/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.21 2006/09/27 14:37:38 claudio Exp $ */
+/* $OpenBSD: packet.c,v 1.22 2006/11/17 08:55:31 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -61,6 +61,36 @@ gen_ospf_hdr(struct buf *buf, struct iface *iface, u_int8_t type)
int
send_packet(struct iface *iface, void *pkt, size_t len, struct sockaddr_in *dst)
{
+ struct msghdr msg;
+ struct iovec iov[2];
+ struct ip ip_hdr;
+
+ /* setup IP hdr */
+ bzero(&ip_hdr, sizeof(ip_hdr));
+ ip_hdr.ip_v = IPVERSION;
+ ip_hdr.ip_hl = sizeof(ip_hdr) >> 2;
+ ip_hdr.ip_tos = IPTOS_PREC_INTERNETCONTROL;
+ ip_hdr.ip_len = htons(len + sizeof(ip_hdr));
+ ip_hdr.ip_id = 0; /* 0 means kernel set appropriate value */
+ ip_hdr.ip_off = 0;
+ ip_hdr.ip_ttl = iface->type != IF_TYPE_VIRTUALLINK ?
+ IP_DEFAULT_MULTICAST_TTL : MAXTTL;
+ ip_hdr.ip_p = IPPROTO_OSPF;
+ ip_hdr.ip_sum = 0;
+ ip_hdr.ip_src = iface->addr;
+ ip_hdr.ip_dst = dst->sin_addr;
+
+ /* setup buffer */
+ bzero(&msg, sizeof(msg));
+ iov[0].iov_base = &ip_hdr;
+ iov[0].iov_len = sizeof(ip_hdr);
+ iov[1].iov_base = pkt;
+ iov[1].iov_len = len;
+ msg.msg_name = dst;
+ msg.msg_namelen = sizeof(*dst);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+
/* set outgoing interface for multicast traffic */
if (IN_MULTICAST(ntohl(dst->sin_addr.s_addr)))
if (if_set_mcast(iface) == -1) {
@@ -69,8 +99,7 @@ send_packet(struct iface *iface, void *pkt, size_t len, struct sockaddr_in *dst)
return (-1);
}
- if (sendto(iface->fd, pkt, len, 0,
- (struct sockaddr *)dst, sizeof(*dst)) == -1 ) {
+ if (sendmsg(iface->fd, &msg, 0) == -1) {
log_warn("send_packet: error sending packet on interface %s",
iface->name);
return (-1);
@@ -105,8 +134,6 @@ recv_packet(int fd, short event, void *bula)
bzero(&msg, sizeof(msg));
iov.iov_base = buf = pkt_ptr;
iov.iov_len = READ_BUF_SIZE;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cbuf;
@@ -143,7 +170,7 @@ recv_packet(int fd, short event, void *bula)
/* find a matching interface */
if ((iface = find_iface(xconf, ifindex, ip_hdr.ip_src)) == NULL) {
- log_debug("recv_packet: cannot find valid interface");
+ /* XXX add a counter here */
return;
}
diff --git a/usr.sbin/ospfd/parse.y b/usr.sbin/ospfd/parse.y
index a3aec6f318d..857df2c0a0e 100644
--- a/usr.sbin/ospfd/parse.y
+++ b/usr.sbin/ospfd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.37 2006/10/29 19:29:09 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.38 2006/11/17 08:55:31 claudio Exp $ */
/*
* Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
@@ -93,7 +93,7 @@ struct sym {
int symset(const char *, const char *, int);
char *symget(const char *);
struct area *conf_get_area(struct in_addr);
-struct iface *conf_get_if(struct kif *);
+struct iface *conf_get_if(struct kif *, struct kif_addr *);
typedef struct {
union {
@@ -413,15 +413,39 @@ areaoptsl : interface
;
interface : INTERFACE STRING {
- struct kif *kif;
+ struct kif *kif;
+ struct kif_addr *ka = NULL;
+ char *s;
+ struct in_addr addr;
+
+ s = strchr($2, ':');
+ if (s) {
+ *s++ = '\0';
+ if (inet_aton(s, &addr) == 0) {
+ yyerror(
+ "error parsing interface address");
+ free($2);
+ YYERROR;
+ }
+ } else
+ addr.s_addr = 0;
- if ((kif = kif_findname($2)) == NULL) {
+ if ((kif = kif_findname($2, addr, &ka)) == NULL) {
yyerror("unknown interface %s", $2);
free($2);
YYERROR;
}
+ if (ka == NULL) {
+ if (s)
+ yyerror("address %s not configured on "
+ "interface %s", s, $2);
+ else
+ yyerror("unnumbered interface %s", $2);
+ free($2);
+ YYERROR;
+ }
free($2);
- iface = conf_get_if(kif);
+ iface = conf_get_if(kif, ka);
if (iface == NULL)
YYERROR;
iface->area = area;
@@ -880,20 +904,21 @@ conf_get_area(struct in_addr id)
}
struct iface *
-conf_get_if(struct kif *kif)
+conf_get_if(struct kif *kif, struct kif_addr *ka)
{
struct area *a;
struct iface *i;
LIST_FOREACH(a, &conf->area_list, entry)
LIST_FOREACH(i, &a->iface_list, entry)
- if (i->ifindex == kif->ifindex) {
+ if (i->ifindex == kif->ifindex &&
+ i->addr.s_addr == ka->addr.s_addr) {
yyerror("interface %s already configured",
kif->ifname);
return (NULL);
}
- i = if_new(kif);
+ i = if_new(kif, ka);
i->auth_keyid = 1;
return (i);