diff options
-rw-r--r-- | usr.sbin/ospfd/interface.c | 159 | ||||
-rw-r--r-- | usr.sbin/ospfd/kroute.c | 124 | ||||
-rw-r--r-- | usr.sbin/ospfd/ospfd.h | 11 | ||||
-rw-r--r-- | usr.sbin/ospfd/ospfe.c | 11 | ||||
-rw-r--r-- | usr.sbin/ospfd/ospfe.h | 7 | ||||
-rw-r--r-- | usr.sbin/ospfd/packet.c | 39 | ||||
-rw-r--r-- | usr.sbin/ospfd/parse.y | 41 |
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); |