diff options
72 files changed, 869 insertions, 264 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index e02617691f..05e67baa8a 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1632,7 +1632,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath, struct aspath *newpath = NULL, *mergedpath; int hops, cpasns = 0; - if (!aspath) + if (!aspath || !as4path) return NULL; seg = aspath->segments; diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 2c52b57b36..6596e7cfa2 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1513,6 +1513,9 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr, if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) { newpath = aspath_reconcile_as4(attr->aspath, as4_path); + if (!newpath) + return BGP_ATTR_PARSE_ERROR; + aspath_unintern(&attr->aspath); attr->aspath = aspath_intern(newpath); } diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 7cf1477549..0ffbe174ed 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -1054,6 +1054,9 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name, struct ecommunity *ecom = NULL; regex_t *regex = NULL; + if (str == NULL) + return COMMUNITY_LIST_ERR_MALFORMED_VAL; + entry = NULL; /* Get community list. */ @@ -1089,7 +1092,7 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name, entry = community_entry_new(); entry->direct = direct; entry->style = style; - entry->any = (str ? 0 : 1); + entry->any = 0; if (ecom) entry->config = ecommunity_ecom2str( ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0); diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c index 69c92e829c..c8d5b1daa1 100644 --- a/bgpd/bgp_io.c +++ b/bgpd/bgp_io.c @@ -174,7 +174,6 @@ static int bgp_process_reads(struct thread *thread) bool more = true; // whether we got more data bool fatal = false; // whether fatal error occurred bool added_pkt = false; // whether we pushed onto ->ibuf - bool header_valid = true; // whether header is valid /* clang-format on */ peer = THREAD_ARG(thread); @@ -214,10 +213,8 @@ static int bgp_process_reads(struct thread *thread) if (ringbuf_remain(ibw) < BGP_HEADER_SIZE) break; - /* validate header */ - header_valid = validate_header(peer); - - if (!header_valid) { + /* check that header is valid */ + if (!validate_header(peer)) { fatal = true; break; } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 28e8ceb15d..3a854be534 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -466,6 +466,7 @@ leak_update( { struct prefix *p = &bn->p; struct bgp_info *bi; + struct bgp_info *bi_ultimate; struct bgp_info *new; char buf_prefix[PREFIX_STRLEN]; @@ -477,6 +478,26 @@ leak_update( } /* + * Routes that are redistributed into BGP from zebra do not get + * nexthop tracking. However, if those routes are subsequently + * imported to other RIBs within BGP, the leaked routes do not + * carry the original BGP_ROUTE_REDISTRIBUTE sub_type. Therefore, + * in order to determine if the route we are currently leaking + * should have nexthop tracking, we must find the ultimate + * parent so we can check its sub_type. + * + * As of now, source_bi may at most be a second-generation route + * (only one hop back to ultimate parent for vrf-vpn-vrf scheme). + * Using a loop here supports more complex intra-bgp import-export + * schemes that could be implemented in the future. + * + */ + for (bi_ultimate = source_bi; + bi_ultimate->extra && bi_ultimate->extra->parent; + bi_ultimate = bi_ultimate->extra->parent) + ; + + /* * match parent */ for (bi = bn->info; bi; bi = bi->next) { @@ -528,7 +549,7 @@ leak_update( bgp_nexthop = bi->extra->bgp_orig; /* No nexthop tracking for redistributed routes */ - if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE) + if (bi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) nh_valid = 1; else /* @@ -591,7 +612,7 @@ leak_update( * their originating protocols will do the tracking and * withdraw those routes if the nexthops become unreachable */ - if (source_bi->sub_type == BGP_ROUTE_REDISTRIBUTE) + if (bi_ultimate->sub_type == BGP_ROUTE_REDISTRIBUTE) nh_valid = 1; else /* diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index fd8d894878..32011d210b 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -438,7 +438,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop, struct bgp_node *rn1, *rn2; struct peer_af *paf; struct prefix p, np; - struct bgp *bgp = NULL; + struct bgp *bgp; np.family = AF_INET; np.prefixlen = IPV4_MAX_BITLEN; @@ -447,7 +447,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop, p.family = AF_INET; p.prefixlen = IPV4_MAX_BITLEN; - rn1 = rn2 = NULL; + rn2 = NULL; bgp = SUBGRP_INST(subgrp); rn1 = bgp_node_match(bgp->connected_table[AFI_IP], &np); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index aa98f8a557..da90bbd67d 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -80,8 +80,9 @@ void bgp_capability_vty_out(struct vty *vty, struct peer *peer, afi_t afi; safi_t safi; - bgp_map_afi_safi_iana2int(ntohs(mpc.afi), mpc.safi, - &afi, &safi); + (void)bgp_map_afi_safi_iana2int(ntohs(mpc.afi), + mpc.safi, &afi, &safi); + if (use_json) { switch (afi) { case AFI_IP: diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 95e7def8fb..0b1deba517 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1318,6 +1318,8 @@ void bgp_attr_add_gshut_community(struct attr *attr) old = attr->community; gshut = community_str2com("graceful-shutdown"); + assert(gshut); + if (old) { merge = community_merge(community_dup(old), gshut); @@ -6564,14 +6566,8 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo, } else { char buf[BUFSIZ]; - if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN)) - snprintf(buf, sizeof(buf), "%s%s", - inet_ntoa(attr->mp_nexthop_global_in), - vrf_id_str); - else - snprintf(buf, sizeof(buf), "%s%s", - inet_ntoa(attr->nexthop), - vrf_id_str); + snprintf(buf, sizeof(buf), "%s%s", + inet_ntoa(attr->nexthop), vrf_id_str); vty_out(vty, "%-16s", buf); } } diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c index cabd5b5cbd..34ddbfcd14 100644 --- a/bgpd/bgp_updgrp_packet.c +++ b/bgpd/bgp_updgrp_packet.c @@ -397,7 +397,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt, vec = &pkt->arr.entries[BGP_ATTR_VEC_NH]; if (CHECK_FLAG(vec->flags, BPKT_ATTRVEC_FLAGS_UPDATED)) { uint8_t nhlen; - afi_t nhafi = AFI_MAX; /* NH AFI is based on nhlen! */ + afi_t nhafi; int route_map_sets_nh; nhlen = stream_getc_from(s, vec->offset); if (peer_cap_enhe(peer, paf->afi, paf->safi)) diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index cc05194703..a771eedf0f 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -125,7 +125,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, if (rd_header) { uint16_t type; - struct rd_as rd_as; + struct rd_as rd_as = {0}; struct rd_ip rd_ip = {0}; #if ENABLE_BGP_VNC struct rd_vnc_eth rd_vnc_eth = { diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 4e0f7155ba..3d1fdfd38d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2009,27 +2009,19 @@ DEFUN (no_bgp_fast_external_failover, CPP_NOTICE("bgpd: remove deprecated '[no] bgp enforce-first-as' commands") #endif -DEFUN_DEPRECATED (bgp_enforce_first_as, - bgp_enforce_first_as_cmd, - "bgp enforce-first-as", - BGP_STR - "Enforce the first AS for EBGP routes\n") +DEFUN_HIDDEN (bgp_enforce_first_as, + bgp_enforce_first_as_cmd, + "[no] bgp enforce-first-as", + NO_STR + BGP_STR + "Enforce the first AS for EBGP routes\n") { VTY_DECLVAR_CONTEXT(bgp, bgp); - bgp_flag_set(bgp, BGP_FLAG_ENFORCE_FIRST_AS); - return CMD_SUCCESS; -} - -DEFUN_DEPRECATED (no_bgp_enforce_first_as, - no_bgp_enforce_first_as_cmd, - "no bgp enforce-first-as", - NO_STR - BGP_STR - "Enforce the first AS for EBGP routes\n") -{ - VTY_DECLVAR_CONTEXT(bgp, bgp); - bgp_flag_unset(bgp, BGP_FLAG_ENFORCE_FIRST_AS); + if (strmatch(argv[0]->text, "no")) + bgp_flag_unset(bgp, BGP_FLAG_ENFORCE_FIRST_AS); + else + bgp_flag_set(bgp, BGP_FLAG_ENFORCE_FIRST_AS); return CMD_SUCCESS; } @@ -6745,6 +6737,11 @@ DEFPY (bgp_imexport_vrf, safi_t safi; afi_t afi; + if (import_name == NULL) { + vty_out(vty, "%% Missing import name\n"); + return CMD_WARNING; + } + if (argv_find(argv, argc, "no", &idx)) remove = true; @@ -11409,7 +11406,6 @@ DEFUN (show_ip_bgp_peer_groups, "Peer group name\n") { char *vrf, *pg; - vrf = pg = NULL; int idx = 0; vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg @@ -12440,7 +12436,6 @@ void bgp_vty_init(void) /* "bgp enforce-first-as" commands */ install_element(BGP_NODE, &bgp_enforce_first_as_cmd); - install_element(BGP_NODE, &no_bgp_enforce_first_as_cmd); /* "bgp bestpath compare-routerid" commands */ install_element(BGP_NODE, &bgp_bestpath_compare_router_id_cmd); diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c index 72255e54fb..8553846c90 100644 --- a/bgpd/rfapi/bgp_rfapi_cfg.c +++ b/bgpd/rfapi/bgp_rfapi_cfg.c @@ -1426,7 +1426,8 @@ DEFUN (vnc_export_nvegroup, if (rfg_new == NULL) { rfg_new = bgp_rfapi_cfg_match_byname(bgp, argv[5]->arg, RFAPI_GROUP_CFG_VRF); - vnc_add_vrf_opener(bgp, rfg_new); + if (rfg_new) + vnc_add_vrf_opener(bgp, rfg_new); } if (rfg_new == NULL) { @@ -4518,7 +4519,7 @@ void bgp_rfapi_show_summary(struct bgp *bgp, struct vty *vty) if (VNC_EXPORT_ZEBRA_GRP_ENABLED(hc)) { redist++; vty_out(vty, "%sToZebra Groups={", (redist == 1 ? "" : " ")); - if (hc->rfg_export_direct_bgp_l) { + if (hc->rfg_export_zebra_l) { int cnt = 0; struct listnode *node, *nnode; struct rfapi_rfg_name *rfgn; diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c index 18a979e531..2f8f132fcd 100644 --- a/bgpd/rfapi/rfapi_vty.c +++ b/bgpd/rfapi/rfapi_vty.c @@ -388,15 +388,11 @@ int rfapiStream2Vty(void *stream, /* input */ return 1; } - if (stream) { - *vty = stream; /* VTYNL requires vty to be legit */ - *fp = (int (*)(void *, const char *, ...))vty_out; - *outstream = stream; - *vty_newline = str_vty_newline(*vty); - return 1; - } - - return 0; + *vty = stream; /* VTYNL requires vty to be legit */ + *fp = (int (*)(void *, const char *, ...))vty_out; + *outstream = stream; + *vty_newline = str_vty_newline(*vty); + return 1; } /* called from bgpd/bgp_vty.c'route_vty_out() */ diff --git a/doc/user/basic.rst b/doc/user/basic.rst index a75017c442..cb46080055 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -405,6 +405,18 @@ These options apply to all |PACKAGE_NAME| daemons. Print program version. +.. option:: --log <stdout|syslog|file:/path/to/log/file> + + When initializing the daemon, setup the log to go to either stdout, + syslog or to a file. These values will be displayed as part of + a show run. Additionally they can be overridden at runtime if + desired via the normal log commands. + +.. option:: --log-level <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging> + + When initializing the daemon, allow the specification of a default + log level at startup from one of the specified levels. + .. _loadable-module-support: Loadable Module Support diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c index 4107d44090..eeefc51968 100644 --- a/eigrpd/eigrp_fsm.c +++ b/eigrpd/eigrp_fsm.c @@ -486,6 +486,7 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg) int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) { + struct eigrp *eigrp; struct eigrp_prefix_entry *prefix = msg->prefix; struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries); @@ -498,9 +499,10 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg) if (msg->packet_type == EIGRP_OPC_QUERY) eigrp_send_reply(msg->adv_router, prefix); prefix->req_action |= EIGRP_FSM_NEED_UPDATE; - listnode_add( - (eigrp_lookup())->topology_changes_internalIPV4, - prefix); + eigrp = eigrp_lookup(); + assert(eigrp); + listnode_add(eigrp->topology_changes_internalIPV4, + prefix); } eigrp_topology_update_node_flags(prefix); eigrp_update_routing_table(prefix); diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index cd459fdc42..cd62811fdf 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -336,6 +336,9 @@ void eigrp_if_free(struct eigrp_interface *ei, int source) struct eigrp_prefix_entry *pe; struct eigrp *eigrp = eigrp_lookup(); + if (!eigrp) + return; + if (source == INTERFACE_DOWN_BY_VTY) { THREAD_OFF(ei->t_hello); eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL); diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c index becb29a95f..8ca0e282a8 100644 --- a/eigrpd/eigrp_topology.c +++ b/eigrpd/eigrp_topology.c @@ -182,6 +182,9 @@ void eigrp_prefix_entry_delete(struct route_table *table, struct eigrp *eigrp = eigrp_lookup(); struct route_node *rn; + if (!eigrp) + return; + rn = route_node_lookup(table, pe->destination); if (!rn) return; @@ -426,6 +429,9 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp) struct eigrp_prefix_entry *pe; struct route_node *rn; + if (!eigrp) + return; + for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) { pe = rn->info; @@ -442,6 +448,8 @@ void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest) struct eigrp_nexthop_entry *entry; struct eigrp *eigrp = eigrp_lookup(); + assert(eigrp); + for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) { if (entry->reported_distance < dest->fdistance) { // is feasible successor, can be successor @@ -471,11 +479,15 @@ void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest) void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix) { struct eigrp *eigrp = eigrp_lookup(); - struct list *successors = - eigrp_topology_get_successor_max(prefix, eigrp->max_paths); + struct list *successors; struct listnode *node; struct eigrp_nexthop_entry *entry; + if (!eigrp) + return; + + successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths); + if (successors) { eigrp_zebra_route_add(prefix->destination, successors); for (ALL_LIST_ELEMENTS_RO(successors, node, entry)) diff --git a/include/linux/netlink.h b/include/linux/netlink.h new file mode 100644 index 0000000000..0b2c29bd08 --- /dev/null +++ b/include/linux/netlink.h @@ -0,0 +1,247 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_NETLINK_H +#define __LINUX_NETLINK_H + +#include <linux/kernel.h> +#include <linux/socket.h> /* for __kernel_sa_family_t */ +#include <linux/types.h> + +#define NETLINK_ROUTE 0 /* Routing/device hook */ +#define NETLINK_UNUSED 1 /* Unused number */ +#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ +#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */ +#define NETLINK_SOCK_DIAG 4 /* socket monitoring */ +#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ +#define NETLINK_XFRM 6 /* ipsec */ +#define NETLINK_SELINUX 7 /* SELinux event notifications */ +#define NETLINK_ISCSI 8 /* Open-iSCSI */ +#define NETLINK_AUDIT 9 /* auditing */ +#define NETLINK_FIB_LOOKUP 10 +#define NETLINK_CONNECTOR 11 +#define NETLINK_NETFILTER 12 /* netfilter subsystem */ +#define NETLINK_IP6_FW 13 +#define NETLINK_DNRTMSG 14 /* DECnet routing messages */ +#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ +#define NETLINK_GENERIC 16 +/* leave room for NETLINK_DM (DM Events) */ +#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ +#define NETLINK_ECRYPTFS 19 +#define NETLINK_RDMA 20 +#define NETLINK_CRYPTO 21 /* Crypto layer */ +#define NETLINK_SMC 22 /* SMC monitoring */ + +#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG + +#define MAX_LINKS 32 + +struct sockaddr_nl { + __kernel_sa_family_t nl_family; /* AF_NETLINK */ + unsigned short nl_pad; /* zero */ + __u32 nl_pid; /* port ID */ + __u32 nl_groups; /* multicast groups mask */ +}; + +struct nlmsghdr { + __u32 nlmsg_len; /* Length of message including header */ + __u16 nlmsg_type; /* Message content */ + __u16 nlmsg_flags; /* Additional flags */ + __u32 nlmsg_seq; /* Sequence number */ + __u32 nlmsg_pid; /* Sending process port ID */ +}; + +/* Flags values */ + +#define NLM_F_REQUEST 0x01 /* It is request message. */ +#define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */ +#define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */ +#define NLM_F_ECHO 0x08 /* Echo this request */ +#define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */ +#define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */ + +/* Modifiers to GET request */ +#define NLM_F_ROOT 0x100 /* specify tree root */ +#define NLM_F_MATCH 0x200 /* return all matching */ +#define NLM_F_ATOMIC 0x400 /* atomic GET */ +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +/* Modifiers to NEW request */ +#define NLM_F_REPLACE 0x100 /* Override existing */ +#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ +#define NLM_F_CREATE 0x400 /* Create, if it does not exist */ +#define NLM_F_APPEND 0x800 /* Add to end of list */ + +/* Modifiers to DELETE request */ +#define NLM_F_NONREC 0x100 /* Do not delete recursively */ + +/* Flags for ACK message */ +#define NLM_F_CAPPED 0x100 /* request was capped */ +#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */ + +/* + 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL + 4.4BSD CHANGE NLM_F_REPLACE + + True CHANGE NLM_F_CREATE|NLM_F_REPLACE + Append NLM_F_CREATE + Check NLM_F_EXCL + */ + +#define NLMSG_ALIGNTO 4U +#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) +#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN) +#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) +#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) +#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ + (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) +#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len <= (len)) +#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) + +#define NLMSG_NOOP 0x1 /* Nothing. */ +#define NLMSG_ERROR 0x2 /* Error */ +#define NLMSG_DONE 0x3 /* End of a dump */ +#define NLMSG_OVERRUN 0x4 /* Data lost */ + +#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ + +struct nlmsgerr { + int error; + struct nlmsghdr msg; + /* + * followed by the message contents unless NETLINK_CAP_ACK was set + * or the ACK indicates success (error == 0) + * message length is aligned with NLMSG_ALIGN() + */ + /* + * followed by TLVs defined in enum nlmsgerr_attrs + * if NETLINK_EXT_ACK was set + */ +}; + +/** + * enum nlmsgerr_attrs - nlmsgerr attributes + * @NLMSGERR_ATTR_UNUSED: unused + * @NLMSGERR_ATTR_MSG: error message string (string) + * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original + * message, counting from the beginning of the header (u32) + * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to + * be used - in the success case - to identify a created + * object or operation or similar (binary) + * @__NLMSGERR_ATTR_MAX: number of attributes + * @NLMSGERR_ATTR_MAX: highest attribute number + */ +enum nlmsgerr_attrs { + NLMSGERR_ATTR_UNUSED, + NLMSGERR_ATTR_MSG, + NLMSGERR_ATTR_OFFS, + NLMSGERR_ATTR_COOKIE, + + __NLMSGERR_ATTR_MAX, + NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 +}; + +#define NETLINK_ADD_MEMBERSHIP 1 +#define NETLINK_DROP_MEMBERSHIP 2 +#define NETLINK_PKTINFO 3 +#define NETLINK_BROADCAST_ERROR 4 +#define NETLINK_NO_ENOBUFS 5 +#define NETLINK_RX_RING 6 +#define NETLINK_TX_RING 7 +#define NETLINK_LISTEN_ALL_NSID 8 +#define NETLINK_LIST_MEMBERSHIPS 9 +#define NETLINK_CAP_ACK 10 +#define NETLINK_EXT_ACK 11 + +struct nl_pktinfo { + __u32 group; +}; + +struct nl_mmap_req { + unsigned int nm_block_size; + unsigned int nm_block_nr; + unsigned int nm_frame_size; + unsigned int nm_frame_nr; +}; + +struct nl_mmap_hdr { + unsigned int nm_status; + unsigned int nm_len; + __u32 nm_group; + /* credentials */ + __u32 nm_pid; + __u32 nm_uid; + __u32 nm_gid; +}; + +enum nl_mmap_status { + NL_MMAP_STATUS_UNUSED, + NL_MMAP_STATUS_RESERVED, + NL_MMAP_STATUS_VALID, + NL_MMAP_STATUS_COPY, + NL_MMAP_STATUS_SKIP, +}; + +#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO +#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT) +#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr)) + +#define NET_MAJOR 36 /* Major 36 is reserved for networking */ + +enum { + NETLINK_UNCONNECTED = 0, + NETLINK_CONNECTED, +}; + +/* + * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * | Header | Pad | Payload | Pad | + * | (struct nlattr) | ing | | ing | + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * <-------------- nlattr->nla_len --------------> + */ + +struct nlattr { + __u16 nla_len; + __u16 nla_type; +}; + +/* + * nla_type (16 bits) + * +---+---+-------------------------------+ + * | N | O | Attribute Type | + * +---+---+-------------------------------+ + * N := Carries nested attributes + * O := Payload stored in network byte order + * + * Note: The N and O flag are mutually exclusive. + */ +#define NLA_F_NESTED (1 << 15) +#define NLA_F_NET_BYTEORDER (1 << 14) +#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) + +#define NLA_ALIGNTO 4 +#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) +#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) + +/* Generic 32 bitflags attribute content sent to the kernel. + * + * The value is a bitmap that defines the values being set + * The selector is a bitmask that defines which value is legit + * + * Examples: + * value = 0x0, and selector = 0x1 + * implies we are selecting bit 1 and we want to set its value to 0. + * + * value = 0x2, and selector = 0x2 + * implies we are selecting bit 2 and we want to set its value to 1. + * + */ +struct nla_bitfield32 { + __u32 value; + __u32 selector; +}; + +#endif /* __LINUX_NETLINK_H */ diff --git a/include/subdir.am b/include/subdir.am index db5ed06c61..731785d4b4 100644 --- a/include/subdir.am +++ b/include/subdir.am @@ -4,6 +4,7 @@ noinst_HEADERS += \ include/linux/lwtunnel.h \ include/linux/mpls_iptunnel.h \ include/linux/neighbour.h \ + include/linux/netlink.h \ include/linux/rtnetlink.h \ include/linux/socket.h \ include/linux/net_namespace.h \ diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index bba86d4c1f..c8ef829064 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -622,7 +622,7 @@ static const char *lsp_bits2string(uint8_t lsp_bits, char *buf, size_t buf_size) pos += sprintf(pos, "%d/", ISIS_MASK_LSP_PARTITION_BIT(lsp_bits) ? 1 : 0); - pos += sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0); + sprintf(pos, "%d", ISIS_MASK_LSP_OL_BIT(lsp_bits) ? 1 : 0); return buf; } @@ -1052,6 +1052,7 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) uint8_t subtlv_len; if (IS_MPLS_TE(isisMplsTE) + && circuit->interface != NULL && HAS_LINK_PARAMS( circuit->interface)) /* Update Local and Remote IP diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 6e56870ebd..fd82b85f51 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -309,9 +309,9 @@ int isis_recv_pdu_p2p(struct isis_circuit *circuit, uint8_t *ssnpa) addr_len = sizeof(s_addr); /* we can read directly to the stream */ - stream_recvfrom(circuit->rcv_stream, circuit->fd, - circuit->interface->mtu, 0, (struct sockaddr *)&s_addr, - (socklen_t *)&addr_len); + (void)stream_recvfrom( + circuit->rcv_stream, circuit->fd, circuit->interface->mtu, 0, + (struct sockaddr *)&s_addr, (socklen_t *)&addr_len); if (s_addr.sll_pkttype == PACKET_OUTGOING) { /* Read the packet into discard buff */ diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index a55a0e1902..2e2933db33 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -77,14 +77,13 @@ enum vertextype { /* * Triple <N, d(N), {Adj(N)}> */ +union isis_N { + uint8_t id[ISIS_SYS_ID_LEN + 1]; + struct prefix prefix; +}; struct isis_vertex { enum vertextype type; - - union { - uint8_t id[ISIS_SYS_ID_LEN + 1]; - struct prefix prefix; - } N; - + union isis_N N; uint32_t d_N; /* d(N) Distance from this IS */ uint16_t depth; /* The depth in the imaginary tree */ struct list *Adj_N; /* {Adj(N)} next hop or neighbor list */ @@ -407,28 +406,28 @@ static const char *vid2string(struct isis_vertex *vertex, char *buff, int size) return "UNKNOWN"; } -static void isis_vertex_id_init(struct isis_vertex *vertex, void *id, +static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n, enum vertextype vtype) { vertex->type = vtype; if (VTYPE_IS(vtype) || VTYPE_ES(vtype)) { - memcpy(vertex->N.id, (uint8_t *)id, ISIS_SYS_ID_LEN + 1); + memcpy(vertex->N.id, n->id, ISIS_SYS_ID_LEN + 1); } else if (VTYPE_IP(vtype)) { - memcpy(&vertex->N.prefix, (struct prefix *)id, - sizeof(struct prefix)); + memcpy(&vertex->N.prefix, &n->prefix, sizeof(struct prefix)); } else { zlog_err("WTF!"); } } -static struct isis_vertex *isis_vertex_new(void *id, enum vertextype vtype) +static struct isis_vertex *isis_vertex_new(union isis_N *n, + enum vertextype vtype) { struct isis_vertex *vertex; vertex = XCALLOC(MTYPE_ISIS_VERTEX, sizeof(struct isis_vertex)); - isis_vertex_id_init(vertex, id, vtype); + isis_vertex_id_init(vertex, n, vtype); vertex->Adj_N = list_new(); vertex->parents = list_new(); @@ -598,17 +597,17 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, #ifdef EXTREME_DEBUG char buff[PREFIX2STR_BUFFER]; #endif /* EXTREME_DEBUG */ - uint8_t id[ISIS_SYS_ID_LEN + 1]; + union isis_N n; - memcpy(id, sysid, ISIS_SYS_ID_LEN); - LSP_PSEUDO_ID(id) = 0; + memcpy(n.id, sysid, ISIS_SYS_ID_LEN); + LSP_PSEUDO_ID(n.id) = 0; lsp = isis_root_system_lsp(spftree->area, spftree->level, sysid); if (lsp == NULL) zlog_warn("ISIS-Spf: could not find own l%d LSP!", spftree->level); - vertex = isis_vertex_new(id, + vertex = isis_vertex_new(&n, spftree->area->oldmetric ? VTYPE_NONPSEUDO_IS : VTYPE_NONPSEUDO_TE_IS); @@ -625,11 +624,12 @@ static struct isis_vertex *isis_spf_add_root(struct isis_spftree *spftree, } static struct isis_vertex *isis_find_vertex(struct isis_vertex_queue *queue, - void *id, enum vertextype vtype) + union isis_N *n, + enum vertextype vtype) { struct isis_vertex querier; - isis_vertex_id_init(&querier, id, vtype); + isis_vertex_id_init(&querier, n, vtype); return hash_lookup(queue->hash, &querier); } @@ -1212,7 +1212,7 @@ static void add_to_paths(struct isis_spftree *spftree, { char buff[PREFIX2STR_BUFFER]; - if (isis_find_vertex(&spftree->paths, vertex->N.id, vertex->type)) + if (isis_find_vertex(&spftree->paths, &vertex->N, vertex->type)) return; isis_vertex_queue_append(&spftree->paths, vertex); diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 6834f52a82..8e53df3b61 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -884,7 +884,7 @@ static uint8_t print_subtlv_use_bw(struct sbuf *buf, int indent, static uint8_t print_unknown_tlv(struct sbuf *buf, int indent, struct subtlv_header *tlvh) { - int i, rtn = 1; + int i, rtn; uint8_t *v = (uint8_t *)tlvh; if (tlvh->length != 0) { diff --git a/isisd/isisd.c b/isisd/isisd.c index 6f04d72082..cecaa0693d 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -1373,7 +1373,7 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level) struct isis_area *area; struct isis_lsp *lsp; struct isis_dynhn *dynhn; - const char *pos = argv; + const char *pos; uint8_t lspid[ISIS_SYS_ID_LEN + 2]; char sysid[255]; uint8_t number[3]; diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c index 39e20ef7c8..ec70ef510a 100644 --- a/ldpd/ldp_debug.c +++ b/ldpd/ldp_debug.c @@ -41,6 +41,9 @@ int ldp_vty_debug(struct vty *vty, const char *negate, const char *type_str, const char *dir_str, const char *all) { + if (type_str == NULL) + return (CMD_WARNING_CONFIG_FAILED); + if (strcmp(type_str, "discovery") == 0) { if (dir_str == NULL) return (CMD_WARNING_CONFIG_FAILED); diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c index 382b006884..4ef57f574a 100644 --- a/ldpd/ldp_vty_conf.c +++ b/ldpd/ldp_vty_conf.c @@ -89,6 +89,9 @@ struct cmd_node ldp_pseudowire_node = int ldp_get_address(const char *str, int *af, union ldpd_addr *addr) { + if (!str || !af || !addr) + return (-1); + memset(addr, 0, sizeof(*addr)); if (inet_pton(AF_INET, str, &addr->v4) == 1) { @@ -428,6 +431,9 @@ ldp_vty_address_family(struct vty *vty, const char *negate, const char *af_str) struct ldpd_af_conf *af_conf; int af; + if (af_str == NULL) + return (CMD_WARNING_CONFIG_FAILED); + if (strcmp(af_str, "ipv4") == 0) { af = AF_INET; af_conf = &vty_conf->ipv4; @@ -709,6 +715,11 @@ ldp_vty_interface(struct vty *vty, const char *negate, const char *ifname) struct iface *iface; struct iface_af *ia; + if (ifname == NULL) { + vty_out (vty, "%% Missing IF name\n"); + return (CMD_WARNING_CONFIG_FAILED); + } + af = ldp_vty_get_af(vty); iface = if_lookup_name(vty_conf, ifname); @@ -776,8 +787,9 @@ ldp_vty_trans_addr(struct vty *vty, const char *negate, const char *addr_str) if (negate) memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr)); else { - if (inet_pton(af, addr_str, &af_conf->trans_addr) != 1 || - bad_addr(af, &af_conf->trans_addr)) { + if (addr_str == NULL + || inet_pton(af, addr_str, &af_conf->trans_addr) != 1 + || bad_addr(af, &af_conf->trans_addr)) { vty_out (vty, "%% Malformed address\n"); return (CMD_SUCCESS); } @@ -797,7 +809,7 @@ ldp_vty_neighbor_targeted(struct vty *vty, const char *negate, const char *addr_ af = ldp_vty_get_af(vty); - if (inet_pton(af, addr_str, &addr) != 1 || + if (addr_str == NULL || inet_pton(af, addr_str, &addr) != 1 || bad_addr(af, &addr)) { vty_out (vty, "%% Malformed address\n"); return (CMD_WARNING_CONFIG_FAILED); @@ -1018,6 +1030,11 @@ ldp_vty_neighbor_password(struct vty *vty, const char *negate, struct in_addr ls size_t password_len; struct nbr_params *nbrp; + if (password_str == NULL) { + vty_out (vty, "%% Missing password\n"); + return (CMD_WARNING_CONFIG_FAILED); + } + if (bad_addr_v4(lsr_id)) { vty_out (vty, "%% Malformed address\n"); return (CMD_WARNING_CONFIG_FAILED); @@ -1113,6 +1130,11 @@ ldp_vty_l2vpn(struct vty *vty, const char *negate, const char *name_str) struct l2vpn_if *lif; struct l2vpn_pw *pw; + if (name_str == NULL) { + vty_out (vty, "%% Missing name\n"); + return (CMD_WARNING_CONFIG_FAILED); + } + l2vpn = l2vpn_find(vty_conf, name_str); if (negate) { @@ -1158,8 +1180,13 @@ ldp_vty_l2vpn_bridge(struct vty *vty, const char *negate, const char *ifname) if (negate) memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname)); - else + else { + if (ifname == NULL) { + vty_out (vty, "%% Missing IF name\n"); + return (CMD_WARNING_CONFIG_FAILED); + } strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname)); + } ldp_config_apply(vty, vty_conf); @@ -1187,6 +1214,11 @@ ldp_vty_l2vpn_pwtype(struct vty *vty, const char *negate, const char *type_str) VTY_DECLVAR_CONTEXT(l2vpn, l2vpn); int pw_type; + if (type_str == NULL) { + vty_out (vty, "%% Missing type\n"); + return (CMD_WARNING_CONFIG_FAILED); + } + if (strcmp(type_str, "ethernet") == 0) pw_type = PW_TYPE_ETHERNET; else @@ -1208,6 +1240,11 @@ ldp_vty_l2vpn_interface(struct vty *vty, const char *negate, const char *ifname) VTY_DECLVAR_CONTEXT(l2vpn, l2vpn); struct l2vpn_if *lif; + if (ifname == NULL) { + vty_out (vty, "%% Missing IF name\n"); + return (CMD_WARNING_CONFIG_FAILED); + } + lif = l2vpn_if_find(l2vpn, ifname); if (negate) { @@ -1246,6 +1283,11 @@ ldp_vty_l2vpn_pseudowire(struct vty *vty, const char *negate, const char *ifname VTY_DECLVAR_CONTEXT(l2vpn, l2vpn); struct l2vpn_pw *pw; + if (ifname == NULL) { + vty_out (vty, "%% Missing IF name\n"); + return (CMD_WARNING_CONFIG_FAILED); + } + pw = l2vpn_pw_find(l2vpn, ifname); if (negate) { @@ -1294,6 +1336,10 @@ ldp_vty_l2vpn_pw_cword(struct vty *vty, const char *negate, const char *preferen if (negate) pw->flags |= F_PW_CWORD_CONF; else { + if (!preference_str) { + vty_out (vty, "%% Missing preference\n"); + return (CMD_WARNING_CONFIG_FAILED); + } if (preference_str[0] == 'e') pw->flags &= ~F_PW_CWORD_CONF; else diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index b265c98dae..b51ff82cea 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -187,6 +187,22 @@ FRR_DAEMON_INFO(ldpd, LDP, .privs = &ldpd_privs, ) +static int ldp_config_fork_apply(struct thread *t) +{ + /* + * So the frr_config_fork() function schedules + * the read of the vty config( if there is a + * non-integrated config ) to be after the + * end of startup and we are starting the + * main process loop. We need to schedule + * the application of this if necessary + * after the read in of the config. + */ + ldp_config_apply(NULL, vty_conf); + + return 0; +} + int main(int argc, char *argv[]) { @@ -195,6 +211,7 @@ main(int argc, char *argv[]) int pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2]; int pipe_parent2lde[2], pipe_parent2lde_sync[2]; char *ctl_sock_name; + struct thread *thread = NULL; ldpd_process = PROC_MAIN; log_procname = log_procnames[ldpd_process]; @@ -331,7 +348,7 @@ main(int argc, char *argv[]) frr_config_fork(); /* apply configuration */ - ldp_config_apply(NULL, vty_conf); + thread_add_event(master, ldp_config_fork_apply, NULL, 0, &thread); /* setup pipes to children */ if ((iev_ldpe = calloc(1, sizeof(struct imsgev))) == NULL || diff --git a/lib/clippy.c b/lib/clippy.c index bcec6c2cca..44dcc02eb8 100644 --- a/lib/clippy.c +++ b/lib/clippy.c @@ -31,9 +31,11 @@ #define pychar wchar_t static wchar_t *wconv(const char *s) { - size_t outlen = mbstowcs(NULL, s, 0); + size_t outlen = s ? mbstowcs(NULL, s, 0) : 0; wchar_t *out = malloc((outlen + 1) * sizeof(wchar_t)); - mbstowcs(out, s, outlen + 1); + + if (outlen > 0) + mbstowcs(out, s, outlen); out[outlen] = 0; return out; } diff --git a/lib/command.c b/lib/command.c index a8e61c6bb4..0bf856f248 100644 --- a/lib/command.c +++ b/lib/command.c @@ -261,8 +261,11 @@ void print_version(const char *progname) char *argv_concat(struct cmd_token **argv, int argc, int shift) { - int cnt = argc - shift; - const char *argstr[cnt]; + int cnt = MAX(argc - shift, 0); + const char *argstr[cnt + 1]; + + if (!cnt) + return NULL; for (int i = 0; i < cnt; i++) argstr[i] = argv[i + shift]->arg; @@ -515,13 +518,6 @@ static int config_write_host(struct vty *vty) host.enable); } - if (zlog_default->default_lvl != LOG_DEBUG) { - vty_out(vty, - "! N.B. The 'log trap' command is deprecated.\n"); - vty_out(vty, "log trap %s\n", - zlog_priority[zlog_default->default_lvl]); - } - if (host.logfile && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) { @@ -2429,7 +2425,8 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel) XFREE(MTYPE_TMP, p); if (!ret) { - vty_out(vty, "can't open logfile %s\n", fname); + if (vty) + vty_out(vty, "can't open logfile %s\n", fname); return CMD_WARNING_CONFIG_FAILED; } @@ -2445,6 +2442,39 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel) return CMD_SUCCESS; } +void command_setup_early_logging(const char *dest, const char *level) +{ + char *token; + + if (level) { + int nlevel = level_match(level); + + if (nlevel != ZLOG_DISABLED) + zlog_default->default_lvl = nlevel; + } + + if (!dest) + return; + + if (strcmp(dest, "stdout") == 0) { + zlog_set_level(ZLOG_DEST_STDOUT, zlog_default->default_lvl); + return; + } + + if (strcmp(dest, "syslog") == 0) { + zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl); + return; + } + + token = strstr(dest, ":"); + if (token == NULL) + return; + + token++; + + set_log_file(NULL, token, zlog_default->default_lvl); +} + DEFUN (config_log_file, config_log_file_cmd, "log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]", @@ -2552,36 +2582,6 @@ DEFUN (no_config_log_facility, return CMD_SUCCESS; } -DEFUN_DEPRECATED( - config_log_trap, config_log_trap_cmd, - "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>", - "Logging control\n" - "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC) -{ - int new_level; - int i; - - if ((new_level = level_match(argv[2]->arg)) == ZLOG_DISABLED) - return CMD_ERR_NO_MATCH; - - zlog_default->default_lvl = new_level; - for (i = 0; i < ZLOG_NUM_DESTS; i++) - if (zlog_default->maxlvl[i] != ZLOG_DISABLED) - zlog_default->maxlvl[i] = new_level; - return CMD_SUCCESS; -} - -DEFUN_DEPRECATED( - no_config_log_trap, no_config_log_trap_cmd, - "no log trap [emergencies|alerts|critical|errors|warnings|notifications|informational|debugging]", - NO_STR - "Logging control\n" - "Permit all logging information\n" LOG_LEVEL_DESC) -{ - zlog_default->default_lvl = LOG_DEBUG; - return CMD_SUCCESS; -} - DEFUN (config_log_record_priority, config_log_record_priority_cmd, "log record-priority", @@ -2871,8 +2871,6 @@ void cmd_init(int terminal) install_element(CONFIG_NODE, &no_config_log_syslog_cmd); install_element(CONFIG_NODE, &config_log_facility_cmd); install_element(CONFIG_NODE, &no_config_log_facility_cmd); - install_element(CONFIG_NODE, &config_log_trap_cmd); - install_element(CONFIG_NODE, &no_config_log_trap_cmd); install_element(CONFIG_NODE, &config_log_record_priority_cmd); install_element(CONFIG_NODE, &no_config_log_record_priority_cmd); diff --git a/lib/command.h b/lib/command.h index 9bf482f41b..2d333b098a 100644 --- a/lib/command.h +++ b/lib/command.h @@ -240,9 +240,6 @@ struct cmd_node { #define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN) -#define DEFUN_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \ - DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_DEPRECATED) - /* DEFUN_NOSH for commands that vtysh should ignore */ #define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \ DEFUN(funcname, cmdname, cmdstr, helpstr) @@ -479,4 +476,5 @@ extern void cmd_variable_handler_register(const struct cmd_variable_handler *cvh); extern char *cmd_variable_comp2str(vector comps, unsigned short cols); +extern void command_setup_early_logging(const char *dest, const char *level); #endif /* _ZEBRA_COMMAND_H */ diff --git a/lib/command_match.c b/lib/command_match.c index 99ec03e0c2..c165305d78 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -608,11 +608,14 @@ static struct cmd_token *disambiguate_tokens(struct cmd_token *first, static struct list *disambiguate(struct list *first, struct list *second, vector vline, unsigned int n) { + assert(first != NULL); + assert(second != NULL); // doesn't make sense for these to be inequal length assert(first->count == second->count); assert(first->count == vector_active(vline) - n + 1); - struct listnode *fnode = listhead(first), *snode = listhead(second); + struct listnode *fnode = listhead_unchecked(first), + *snode = listhead_unchecked(second); struct cmd_token *ftok = listgetdata(fnode), *stok = listgetdata(snode), *best = NULL; diff --git a/lib/imsg.c b/lib/imsg.c index 6419f805ab..5424140720 100644 --- a/lib/imsg.c +++ b/lib/imsg.c @@ -77,7 +77,7 @@ ssize_t imsg_read(struct imsgbuf *ibuf) char buf[CMSG_SPACE(sizeof(int) * 1)]; } cmsgbuf; struct iovec iov; - ssize_t n = -1; + ssize_t n; int fd; struct imsg_fd *ifd; @@ -110,7 +110,8 @@ again: return (-1); } - if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) { + n = recvmsg(ibuf->fd, &msg, 0); + if (n == -1) { if (errno == EINTR) goto again; goto fail; diff --git a/lib/libfrr.c b/lib/libfrr.c index 88203fbeb6..9ea5e985cd 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -78,6 +78,8 @@ static void opt_extend(const struct optspec *os) #define OPTION_VTYSOCK 1000 #define OPTION_MODULEDIR 1002 +#define OPTION_LOG 1003 +#define OPTION_LOGLEVEL 1004 static const struct option lo_always[] = { {"help", no_argument, NULL, 'h'}, @@ -86,6 +88,8 @@ static const struct option lo_always[] = { {"module", no_argument, NULL, 'M'}, {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, + {"log", required_argument, NULL, OPTION_LOG}, + {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, {NULL}}; static const struct optspec os_always = { "hvdM:", @@ -94,7 +98,9 @@ static const struct optspec os_always = { " -d, --daemon Runs in daemon mode\n" " -M, --module Load specified module\n" " --vty_socket Override vty socket path\n" - " --moduledir Override modules directory\n", + " --moduledir Override modules directory\n" + " --log Set Logging to stdout, syslog, or file:<name>\n" + " --log-level Set Logging Level to use, debug, info, warn, etc\n", lo_always}; @@ -444,6 +450,12 @@ static int frr_opt(int opt) return 1; di->privs->group = optarg; break; + case OPTION_LOG: + di->early_logging = optarg; + break; + case OPTION_LOGLEVEL: + di->early_loglevel = optarg; + break; default: return 1; } @@ -543,9 +555,8 @@ struct thread_master *frr_init(void) openzlog(di->progname, di->logname, di->instance, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); -#if defined(HAVE_CUMULUS) - zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl); -#endif + + command_setup_early_logging(di->early_logging, di->early_loglevel); if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len, frr_zclientpath)) { @@ -721,15 +732,37 @@ static void frr_daemonize(void) frr_daemon_wait(fds[0]); } +/* + * Why is this a thread? + * + * The read in of config for integrated config happens *after* + * thread execution starts( because it is passed in via a vtysh -b -n ) + * While if you are not using integrated config we want the ability + * to read the config in after thread execution starts, so that + * we can match this behavior. + */ +static int frr_config_read_in(struct thread *t) +{ + if (!vty_read_config(di->config_file, config_default) && + di->backup_config_file) { + zlog_info("Attempting to read backup config file: %s specified", + di->backup_config_file); + vty_read_config(di->backup_config_file, config_default); + } + return 0; +} + void frr_config_fork(void) { hook_call(frr_late_init, master); - vty_read_config(di->config_file, config_default); - /* Don't start execution if we are in dry-run mode */ - if (di->dryrun) + if (di->dryrun) { + frr_config_read_in(NULL); exit(0); + } + + thread_add_event(master, frr_config_read_in, NULL, 0, &di->read_in); if (di->daemon_mode || di->terminal) frr_daemonize(); @@ -813,7 +846,9 @@ static int frr_daemon_ctl(struct thread *t) switch (buf[0]) { case 'S': /* SIGTSTP */ vty_stdio_suspend(); - send(daemon_ctl_sock, "s", 1, 0); + if (send(daemon_ctl_sock, "s", 1, 0) < 0) + zlog_err("%s send(\"s\") error (SIGTSTP propagation)", + (di && di->name ? di->name : "")); break; case 'R': /* SIGTCNT [implicit] */ vty_stdio_resume(); diff --git a/lib/libfrr.h b/lib/libfrr.h index 7ffa780bfb..d255279906 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -50,11 +50,16 @@ struct frr_daemon_info { bool dryrun; bool daemon_mode; bool terminal; + + struct thread *read_in; const char *config_file; + const char *backup_config_file; const char *pid_file; const char *vty_path; const char *module_path; const char *pathspace; + const char *early_logging; + const char *early_loglevel; const char *proghelp; void (*printhelp)(FILE *target); diff --git a/lib/linklist.h b/lib/linklist.h index 39e70293d2..1e2631ea46 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -52,7 +52,9 @@ struct list { }; #define listnextnode(X) ((X) ? ((X)->next) : NULL) +#define listnextnode_unchecked(X) ((X)->next) #define listhead(X) ((X) ? ((X)->head) : NULL) +#define listhead_unchecked(X) ((X)->head) #define listtail(X) ((X) ? ((X)->tail) : NULL) #define listcount(X) ((X)->count) #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL) diff --git a/lib/plist.c b/lib/plist.c index 5ed1589f45..056b737f54 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -850,6 +850,11 @@ static int vty_prefix_list_install(struct vty *vty, afi_t afi, const char *name, int lenum = 0; int genum = 0; + if (name == NULL || prefix == NULL || typestr == NULL) { + vty_out(vty, "%% Missing prefix or type\n"); + return CMD_WARNING_CONFIG_FAILED; + } + /* Sequential number. */ if (seq) seqnum = (int64_t)atol(seq); diff --git a/lib/privs.c b/lib/privs.c index cfe7d6d6f8..7c99742d34 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -824,6 +824,19 @@ void zprivs_init(struct zebra_privs_t *zprivs) #ifdef HAVE_CAPABILITIES zprivs_caps_init(zprivs); + + /* + * If we have initialized the system with no requested + * capabilities, change will not have been set + * to anything by zprivs_caps_init, As such + * we should make sure that when we attempt + * to raize privileges that we actually have + * a do nothing function to call instead of a + * crash :). + */ + if (!zprivs->change) + zprivs->change = zprivs_change_null; + #else /* !HAVE_CAPABILITIES */ /* we dont have caps. we'll need to maintain rid and saved uid * and change euid back to saved uid (who we presume has all neccessary diff --git a/lib/sbuf.c b/lib/sbuf.c index 37c1e5283d..03a2be3e09 100644 --- a/lib/sbuf.c +++ b/lib/sbuf.c @@ -63,13 +63,12 @@ void sbuf_push(struct sbuf *buf, int indent, const char *format, ...) int written; if (!buf->fixed) { - char dummy; int written1, written2; size_t new_size; - written1 = snprintf(&dummy, 0, "%*s", indent, ""); + written1 = indent; va_start(args, format); - written2 = vsnprintf(&dummy, 0, format, args); + written2 = vsnprintf(NULL, 0, format, args); va_end(args); new_size = buf->size; diff --git a/lib/sockopt.c b/lib/sockopt.c index 1d8d9990df..815be86c2e 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -457,8 +457,7 @@ int setsockopt_ifindex(int af, int sock, ifindex_t val) */ static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh) { - /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */ - ifindex_t ifindex = -1; + ifindex_t ifindex; #if defined(IP_PKTINFO) /* Linux pktinfo based ifindex retrieval */ @@ -466,7 +465,11 @@ static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh) pktinfo = (struct in_pktinfo *)getsockopt_cmsg_data(msgh, IPPROTO_IP, IP_PKTINFO); - /* XXX Can pktinfo be NULL? Clean up post 0.98. */ + + /* getsockopt_ifindex() will forward this, being 0 "not found" */ + if (pktinfo == NULL) + return 0; + ifindex = pktinfo->ipi_ifindex; #elif defined(IP_RECVIF) diff --git a/lib/sockunion.c b/lib/sockunion.c index 28a7f647cb..44378b5363 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -46,6 +46,9 @@ int str2sockunion(const char *str, union sockunion *su) { int ret; + if (str == NULL) + return -1; + memset(su, 0, sizeof(union sockunion)); ret = inet_pton(AF_INET, str, &su->sin.sin_addr); @@ -2462,12 +2462,13 @@ static FILE *vty_use_backup_config(const char *fullpath) } /* Read up configuration file from file_name. */ -void vty_read_config(const char *config_file, char *config_default_dir) +bool vty_read_config(const char *config_file, char *config_default_dir) { char cwd[MAXPATHLEN]; FILE *confp = NULL; const char *fullpath; char *tmp = NULL; + bool read_success = false; /* If -f flag specified. */ if (config_file != NULL) { @@ -2525,8 +2526,10 @@ void vty_read_config(const char *config_file, char *config_default_dir) if (strstr(config_default_dir, "vtysh") == NULL) { ret = stat(integrate_default, &conf_stat); - if (ret >= 0) + if (ret >= 0) { + read_success = true; goto tmp_free_and_out; + } } #endif /* VTYSH */ confp = fopen(config_default_dir, "r"); @@ -2550,6 +2553,7 @@ void vty_read_config(const char *config_file, char *config_default_dir) } vty_read_file(confp); + read_success = true; fclose(confp); @@ -2558,6 +2562,8 @@ void vty_read_config(const char *config_file, char *config_default_dir) tmp_free_and_out: if (tmp) XFREE(MTYPE_TMP, tmp); + + return read_success; } /* Small utility function which output log to the VTY. */ @@ -242,7 +242,7 @@ extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); extern void vty_endframe(struct vty *, const char *); bool vty_set_include(struct vty *vty, const char *regexp); -extern void vty_read_config(const char *, char *); +extern bool vty_read_config(const char *, char *); extern void vty_time_print(struct vty *, int); extern void vty_serv_sock(const char *, unsigned short, const char *); extern void vty_close(struct vty *); diff --git a/nhrpd/vici.c b/nhrpd/vici.c index e6111f9d71..3bb0d8308e 100644 --- a/nhrpd/vici.c +++ b/nhrpd/vici.c @@ -287,6 +287,7 @@ static void vici_recv_sa(struct vici_conn *vici, struct zbuf *msg, int event) char buf[32]; struct handle_sa_ctx ctx = { .event = event, + .msgctx.nsections = 0 }; vici_parse_message(vici, msg, parse_sa_message, &ctx.msgctx); diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index b3aa3b21d2..7bccc78e00 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -161,9 +161,10 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, && route->type != OSPF6_DEST_TYPE_RANGE && ((route->type != OSPF6_DEST_TYPE_ROUTER) || !CHECK_FLAG(route->path.router_bits, OSPF6_ROUTER_BIT_E))) { - if (is_debug) - zlog_debug( - "Route type is none of network, range nor ASBR, ignore"); +#if 0 + zlog_debug( + "Route type is none of network, range nor ASBR, ignore"); +#endif return 0; } @@ -177,16 +178,17 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, /* do not generate if the path's area is the same as target area */ if (route->path.area_id == area->area_id) { - if (is_debug) - zlog_debug("The route is in the area itself, ignore"); +#if 0 + zlog_debug("The route is in the area itself, ignore"); +#endif return 0; } /* do not generate if the nexthops belongs to the target area */ if (ospf6_abr_nexthops_belong_to_area(route, area)) { - if (is_debug) - zlog_debug( - "The route's nexthop is in the same area, ignore"); +#if 0 + zlog_debug("The route's nexthop is in the same area, ignore"); +#endif return 0; } @@ -641,6 +643,11 @@ void ospf6_abr_originate_summary(struct ospf6_route *route) if (route->type == OSPF6_DEST_TYPE_NETWORK) { oa = ospf6_area_lookup(route->path.area_id, ospf6); + if (!oa) { + zlog_err("OSPFv6 area lookup failed"); + return; + } + range = ospf6_route_lookup_bestmatch(&route->prefix, oa->range_table); if (range) { @@ -864,7 +871,8 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) lsa->header); prefix.family = AF_INET6; prefix.prefixlen = prefix_lsa->prefix.prefix_length; - ospf6_prefix_in6_addr(&prefix.u.prefix6, &prefix_lsa->prefix); + ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa, + &prefix_lsa->prefix); if (is_debug) prefix2str(&prefix, buf, sizeof(buf)); table = oa->ospf6->route_table; @@ -1284,7 +1292,7 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, (struct ospf6_inter_prefix_lsa *)OSPF6_LSA_HEADER_END( lsa->header); - ospf6_prefix_in6_addr(&in6, &prefix_lsa->prefix); + ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix); if (buf) { inet_ntop(AF_INET6, &in6, buf, buflen); sprintf(&buf[strlen(buf)], "/%d", diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 7f575ee506..a723396507 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -497,7 +497,8 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa) route->type = OSPF6_DEST_TYPE_NETWORK; route->prefix.family = AF_INET6; route->prefix.prefixlen = external->prefix.prefix_length; - ospf6_prefix_in6_addr(&route->prefix.u.prefix6, &external->prefix); + ospf6_prefix_in6_addr(&route->prefix.u.prefix6, external, + &external->prefix); route->path.area_id = asbr_entry->path.area_id; route->path.origin.type = lsa->header->type; @@ -576,7 +577,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, route_to_del->type = OSPF6_DEST_TYPE_NETWORK; route_to_del->prefix.family = AF_INET6; route_to_del->prefix.prefixlen = external->prefix.prefix_length; - ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, + ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6, external, &external->prefix); route_to_del->path.origin.type = lsa->header->type; @@ -603,7 +604,7 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa, memset(&prefix, 0, sizeof(struct prefix)); prefix.family = AF_INET6; prefix.prefixlen = external->prefix.prefix_length; - ospf6_prefix_in6_addr(&prefix.u.prefix6, &external->prefix); + ospf6_prefix_in6_addr(&prefix.u.prefix6, external, &external->prefix); route = ospf6_route_lookup(&prefix, ospf6->route_table); if (route == NULL) { @@ -1705,7 +1706,8 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa, lsa->header); if (pos == 0) { - ospf6_prefix_in6_addr(&in6, &external->prefix); + ospf6_prefix_in6_addr(&in6, external, + &external->prefix); prefix_length = external->prefix.prefix_length; } else { in6 = *((struct in6_addr diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 2059d84868..ae26668c8a 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -347,6 +347,7 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa, "Received is newer, remove requesting"); if (req == on->last_ls_req) { ospf6_lsa_unlock(req); + req = NULL; on->last_ls_req = NULL; } if (req) diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index d99541ebad..0ce08a61e2 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -1323,6 +1323,8 @@ static void ospf6_intra_prefix_update_route_origin(struct ospf6_route *oa_route) g_route = ospf6_route_lookup(&oa_route->prefix, ospf6->route_table); + assert(g_route); + for (ospf6_route_lock(g_route); g_route && ospf6_route_is_prefix(&oa_route->prefix, g_route); g_route = nroute) { @@ -1698,7 +1700,8 @@ void ospf6_intra_prefix_lsa_add(struct ospf6_lsa *lsa) memset(&route->prefix, 0, sizeof(struct prefix)); route->prefix.family = AF_INET6; route->prefix.prefixlen = op->prefix_length; - ospf6_prefix_in6_addr(&route->prefix.u.prefix6, op); + ospf6_prefix_in6_addr(&route->prefix.u.prefix6, + intra_prefix_lsa, op); route->type = OSPF6_DEST_TYPE_NETWORK; route->path.origin.type = lsa->header->type; @@ -1880,7 +1883,7 @@ void ospf6_intra_prefix_lsa_remove(struct ospf6_lsa *lsa) memset(&prefix, 0, sizeof(struct prefix)); prefix.family = AF_INET6; prefix.prefixlen = op->prefix_length; - ospf6_prefix_in6_addr(&prefix.u.prefix6, op); + ospf6_prefix_in6_addr(&prefix.u.prefix6, intra_prefix_lsa, op); route = ospf6_route_lookup(&prefix, oa->route_table); if (route == NULL) diff --git a/ospf6d/ospf6_proto.c b/ospf6d/ospf6_proto.c index 4b56a64b7f..864974c9a4 100644 --- a/ospf6d/ospf6_proto.c +++ b/ospf6d/ospf6_proto.c @@ -24,6 +24,16 @@ #include "ospf6_proto.h" +void ospf6_prefix_in6_addr(struct in6_addr *in6, const void *prefix_buf, + const struct ospf6_prefix *p) +{ + ptrdiff_t in6_off = (caddr_t)p->addr - (caddr_t)prefix_buf; + + memset(in6, 0, sizeof(struct in6_addr)); + memcpy(in6, (uint8_t *)prefix_buf + in6_off, + OSPF6_PREFIX_SPACE(p->prefix_length)); +} + void ospf6_prefix_apply_mask(struct ospf6_prefix *op) { uint8_t *pnt, mask; diff --git a/ospf6d/ospf6_proto.h b/ospf6d/ospf6_proto.h index ca2804c476..c9e7b549db 100644 --- a/ospf6d/ospf6_proto.h +++ b/ospf6d/ospf6_proto.h @@ -84,13 +84,8 @@ struct ospf6_prefix { #define OSPF6_PREFIX_NEXT(x) \ ((struct ospf6_prefix *)((caddr_t)(x) + OSPF6_PREFIX_SIZE(x))) -#define ospf6_prefix_in6_addr(in6, op) \ - do { \ - memset(in6, 0, sizeof(struct in6_addr)); \ - memcpy(in6, (caddr_t)(op) + sizeof(struct ospf6_prefix), \ - OSPF6_PREFIX_SPACE((op)->prefix_length)); \ - } while (0) - +extern void ospf6_prefix_in6_addr(struct in6_addr *in6, const void *prefix_buf, + const struct ospf6_prefix *p); extern void ospf6_prefix_apply_mask(struct ospf6_prefix *op); extern void ospf6_prefix_options_printbuf(uint8_t prefix_options, char *buf, int size); diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index 28c3459825..5b6691e6bf 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -677,6 +677,10 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason) { unsigned long delay, elapsed, ht; + /* OSPF instance does not exist. */ + if (ospf6 == NULL) + return; + ospf6_set_spf_reason(ospf6, reason); if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) { @@ -686,10 +690,6 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason) rbuf); } - /* OSPF instance does not exist. */ - if (ospf6 == NULL) - return; - /* SPF calculation timer is already scheduled. */ if (ospf6->t_spf_calc) { if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c index 8369dde822..b1175a2f68 100644 --- a/ospfd/ospf_api.c +++ b/ospfd/ospf_api.c @@ -510,17 +510,18 @@ struct msg *new_msg_originate_request(uint32_t seqnum, struct in_addr ifaddr, struct msg_originate_request *omsg; unsigned int omsglen; char buf[OSPF_API_MAX_MSG_SIZE]; + size_t off_data = offsetof(struct msg_originate_request, data); + size_t data_maxs = sizeof(buf) - off_data; + struct lsa_header *omsg_data = (struct lsa_header *)&buf[off_data]; omsg = (struct msg_originate_request *)buf; omsg->ifaddr = ifaddr; omsg->area_id = area_id; omsglen = ntohs(data->length); - if (omsglen - > sizeof(buf) - offsetof(struct msg_originate_request, data)) - omsglen = sizeof(buf) - - offsetof(struct msg_originate_request, data); - memcpy(&omsg->data, data, omsglen); + if (omsglen > data_maxs) + omsglen = data_maxs; + memcpy(omsg_data, data, omsglen); omsglen += sizeof(struct msg_originate_request) - sizeof(struct lsa_header); @@ -630,6 +631,9 @@ struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum, uint8_t buf[OSPF_API_MAX_MSG_SIZE]; struct msg_lsa_change_notify *nmsg; unsigned int len; + size_t off_data = offsetof(struct msg_lsa_change_notify, data); + size_t data_maxs = sizeof(buf) - off_data; + struct lsa_header *nmsg_data = (struct lsa_header *)&buf[off_data]; assert(data); @@ -640,10 +644,9 @@ struct msg *new_msg_lsa_change_notify(uint8_t msgtype, uint32_t seqnum, memset(&nmsg->pad, 0, sizeof(nmsg->pad)); len = ntohs(data->length); - if (len > sizeof(buf) - offsetof(struct msg_lsa_change_notify, data)) - len = sizeof(buf) - - offsetof(struct msg_lsa_change_notify, data); - memcpy(&nmsg->data, data, len); + if (len > data_maxs) + len = data_maxs; + memcpy(nmsg_data, data, len); len += sizeof(struct msg_lsa_change_notify) - sizeof(struct lsa_header); return msg_new(msgtype, nmsg, seqnum, len); diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index 37735e3611..8f8900e147 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -1741,6 +1741,8 @@ struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa) struct ospf_lsa *new = NULL; struct ospf *ospf; + assert(lsa); + ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); assert(ospf); @@ -1751,6 +1753,7 @@ struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa) dump_lsa_key(lsa)); lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); /* Flush it anyway. */ + goto out; } if (IS_LSA_MAXAGE(lsa)) { diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index d425624862..c799a4b30f 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -582,7 +582,7 @@ static int ospf_ase_route_match_same(struct route_table *rt, /* Check each path. */ for (n1 = listhead(or->paths), n2 = listhead(newor->paths); n1 && n2; - n1 = listnextnode(n1), n2 = listnextnode(n2)) { + n1 = listnextnode_unchecked(n1), n2 = listnextnode_unchecked(n2)) { op = listgetdata(n1); newop = listgetdata(n2); diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c index b964bbab74..b36f2f4652 100644 --- a/ospfd/ospf_route.c +++ b/ospfd/ospf_route.c @@ -170,8 +170,8 @@ int ospf_route_match_same(struct route_table *rt, struct prefix_ipv4 *prefix, /* Check each path. */ for (n1 = listhead(or->paths), n2 = listhead(newor->paths); - n1 && n2; - n1 = listnextnode(n1), n2 = listnextnode(n2)) { + n1 && n2; n1 = listnextnode_unchecked(n1), + n2 = listnextnode_unchecked(n2)) { op = listgetdata(n1); newop = listgetdata(n2); diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index 2b1b328617..86125d0c76 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -2051,12 +2051,11 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, struct tlv_header *tlvh0, uint16_t subtotal, uint16_t total) { - struct tlv_header *tlvh, *next; + struct tlv_header *tlvh; uint16_t sum = subtotal; for (tlvh = tlvh0; sum < total; - tlvh = (next ? next : TLV_HDR_NEXT(tlvh))) { - next = NULL; + tlvh = TLV_HDR_NEXT(tlvh)) { switch (ntohs(tlvh->type)) { case TE_LINK_SUBTLV_LINK_TYPE: sum += show_vty_link_subtlv_link_type(vty, tlvh); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 31cffea7f2..ddf9133ed9 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -2412,8 +2412,8 @@ DEFUN (ospf_neighbor_poll_interval, int idx_poll = 3; int idx_pri = 5; struct in_addr nbr_addr; - unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT; - unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT; + unsigned int priority; + unsigned int interval; if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) { vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n"); @@ -2422,8 +2422,8 @@ DEFUN (ospf_neighbor_poll_interval, interval = strtoul(argv[idx_poll]->arg, NULL, 10); - if (argc > 4) - priority = strtoul(argv[idx_pri]->arg, NULL, 10); + priority = argc > 4 ? strtoul(argv[idx_pri]->arg, NULL, 10) + : OSPF_NEIGHBOR_PRIORITY_DEFAULT; ospf_nbr_nbma_set(ospf, nbr_addr); ospf_nbr_nbma_poll_interval_set(ospf, nbr_addr, interval); @@ -8166,6 +8166,11 @@ DEFUN (ospf_redistribute_instance_source, source = proto_redistnum(AFI_IP, argv[idx_ospf_table]->text); + if (source < 0) { + vty_out(vty, "Unknown instance redistribution\n"); + return CMD_WARNING_CONFIG_FAILED; + } + instance = strtoul(argv[idx_number]->arg, NULL, 10); if ((source == ZEBRA_ROUTE_OSPF) && !ospf->instance) { diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 141ece9c7a..0a7776cced 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -670,6 +670,16 @@ int ospf_redistribute_set(struct ospf *ospf, int type, unsigned short instance, struct ospf_redist *red; red = ospf_redist_lookup(ospf, type, instance); + + if (red == NULL) { + zlog_err( + "Redistribute[%s][%d]: Lookup failed Type[%d] , Metric[%d]", + ospf_redist_string(type), instance, + metric_type(ospf, type, instance), + metric_value(ospf, type, instance)); + return CMD_WARNING_CONFIG_FAILED; + } + if (ospf_is_type_redistributed(ospf, type, instance)) { if (mtype != red->dmetric.type) { red->dmetric.type = mtype; diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 4cf38439c6..f315421843 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -243,13 +243,14 @@ static struct ospf *ospf_new(unsigned short instance, const char *name) zlog_debug( "%s: Create new ospf instance with vrf_name %s vrf_id %u", __PRETTY_FUNCTION__, name, new->vrf_id); - if (vrf) - ospf_vrf_link(new, vrf); } else { new->vrf_id = VRF_DEFAULT; vrf = vrf_lookup_by_id(VRF_DEFAULT); - ospf_vrf_link(new, vrf); } + + if (vrf) + ospf_vrf_link(new, vrf); + ospf_zebra_vrf_register(new); new->abr_type = OSPF_ABR_DEFAULT; diff --git a/pimd/mtracebis.c b/pimd/mtracebis.c index 731fdb1beb..c0d95aeed9 100644 --- a/pimd/mtracebis.c +++ b/pimd/mtracebis.c @@ -266,6 +266,8 @@ static int recv_response(int fd, int *hops, struct igmp_mtrace *mtracer) int mtrace_len; int responses; unsigned short sum; + size_t mtrace_off; + size_t ip_len; recvd = recvfrom(fd, mtrace_buf, IP_AND_MTRACE_BUF_LEN, 0, NULL, 0); @@ -292,17 +294,20 @@ static int recv_response(int fd, int *hops, struct igmp_mtrace *mtracer) if (sum != in_cksum(ip, ip->ip_hl * 4)) return -1; - mtrace = (struct igmp_mtrace *)(mtrace_buf + (4 * ip->ip_hl)); - - mtrace_len = ntohs(ip->ip_len) - ip->ip_hl * 4; - - if ((char *)mtrace + mtrace_len - > (char *)mtrace_buf + IP_AND_MTRACE_BUF_LEN) + /* Header overflow check */ + mtrace_off = 4 * ip->ip_hl; + if (mtrace_off > MTRACE_BUF_LEN) return -1; - if (mtrace_len < (int)MTRACE_HDR_SIZE) + /* Underflow/overflow check */ + ip_len = ntohs(ip->ip_len); + if (ip_len < mtrace_off || ip_len < MTRACE_HDR_SIZE + || ip_len > MTRACE_BUF_LEN) return -1; + mtrace_len = ip_len - mtrace_off; + mtrace = (struct igmp_mtrace *)(mtrace_buf + mtrace_off); + sum = mtrace->checksum; mtrace->checksum = 0; if (sum != in_cksum(mtrace, mtrace_len)) { @@ -336,7 +341,7 @@ static int wait_for_response(int fd, int *hops, struct igmp_mtrace *mtrace, { fd_set readfds; struct timeval timeout; - int ret = -1; + int ret; long msec, rmsec, tmsec; FD_ZERO(&readfds); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 55222ecddb..123c47568c 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -4504,8 +4504,8 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill, json_object *json_source = NULL; json_object *json_oil = NULL; json_object *json_ifp_out = NULL; - int found_oif = 0; - int first = 1; + int found_oif; + int first; char grp_str[INET_ADDRSTRLEN]; char src_str[INET_ADDRSTRLEN]; char in_ifname[INTERFACE_NAMSIZ + 1]; diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index 673e2ca5b8..95d0278a34 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -817,7 +817,7 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr, * Previous-hop router not known, * packet is sent to an appropriate multicast address */ - inet_aton(MCAST_ALL_ROUTERS, &nh_addr); + (void)inet_aton(MCAST_ALL_ROUTERS, &nh_addr); } /* 6.2.2 8. If this router is the Rendez-vous Point */ diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index de09b070f4..f506875282 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -521,7 +521,7 @@ int pim_msg_send(int fd, struct in_addr src, struct in_addr dst, socklen_t tolen; unsigned char buffer[10000]; unsigned char *msg_start; - uint8_t ttl = MAXTTL; + uint8_t ttl; struct pim_msg_header *header; struct ip *ip; diff --git a/ripd/ripd.c b/ripd/ripd.c index 92c27106d5..90dc7808eb 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -799,11 +799,11 @@ static int rip_auth_simple_password(struct rte *rte, struct sockaddr_in *from, struct interface *ifp) { struct rip_interface *ri; - char *auth_str = (char *)&rte->prefix; + char *auth_str = (char *)rte + offsetof(struct rte, prefix); int i; /* reject passwords with zeros in the middle of the string */ - for (i = strlen(auth_str); i < 16; i++) { + for (i = strnlen(auth_str, 16); i < 16; i++) { if (auth_str[i] != '\0') return 0; } diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index a478b416bf..22a19da0b3 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -51,7 +51,6 @@ uint32_t installed_routes = 0; uint32_t removed_routes = 0; zebra_capabilities_t _caps_p[] = { - ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, }; struct zebra_privs_t sharp_privs = { diff --git a/tests/Makefile.am b/tests/Makefile.am index 9b60312cef..32d2db768a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -102,8 +102,6 @@ lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@" -isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ - isisd/test_fuzz_isis_tlv_tests.h noinst_HEADERS = \ ./helpers/c/prng.h \ @@ -146,6 +144,9 @@ bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c bgpd_test_mpath_SOURCES = bgpd/test_mpath.c isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c +nodist_isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv_tests.h +BUILT_SOURCES=isisd/test_fuzz_isis_tlv_tests.h +CLEANFILES=isisd/test_fuzz_isis_tlv_tests.h isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd isisd_test_isis_vertex_queue_SOURCES = isisd/test_isis_vertex_queue.c diff --git a/tools/start-stop-daemon.c b/tools/start-stop-daemon.c index 8c3fe0c3c5..de58e0a20e 100644 --- a/tools/start-stop-daemon.c +++ b/tools/start-stop-daemon.c @@ -1024,8 +1024,10 @@ int main(int argc, char **argv) close(i); /* change tty */ fd = open("/dev/tty", O_RDWR); - ioctl(fd, TIOCNOTTY, 0); - close(fd); + if (fd >= 0) { + ioctl(fd, TIOCNOTTY, 0); + close(fd); + } chdir("/"); umask(022); /* set a default for dumb programs */ setpgid(0, 0); /* set the process group */ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 309493b13e..0697cd8b75 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2415,10 +2415,11 @@ DEFUNSH(VTYSH_ALL, vtysh_log_syslog, vtysh_log_syslog_cmd, } DEFUNSH(VTYSH_ALL, no_vtysh_log_syslog, no_vtysh_log_syslog_cmd, - "no log syslog [LEVEL]", NO_STR + "no log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]", + NO_STR "Logging control\n" "Cancel logging to syslog\n" - "Logging level\n") + LOG_LEVEL_DESC) { return CMD_SUCCESS; } @@ -2440,24 +2441,6 @@ DEFUNSH(VTYSH_ALL, no_vtysh_log_facility, no_vtysh_log_facility_cmd, return CMD_SUCCESS; } -DEFUNSH_DEPRECATED( - VTYSH_ALL, vtysh_log_trap, vtysh_log_trap_cmd, - "log trap <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>", - "Logging control\n" - "(Deprecated) Set logging level and default for all destinations\n" LOG_LEVEL_DESC) -{ - return CMD_SUCCESS; -} - -DEFUNSH_DEPRECATED(VTYSH_ALL, no_vtysh_log_trap, no_vtysh_log_trap_cmd, - "no log trap [LEVEL]", NO_STR - "Logging control\n" - "Permit all logging information\n" - "Logging level\n") -{ - return CMD_SUCCESS; -} - DEFUNSH(VTYSH_ALL, vtysh_log_record_priority, vtysh_log_record_priority_cmd, "log record-priority", "Logging control\n" @@ -2634,8 +2617,13 @@ static void backup_config_file(const char *fbackup) strcat(integrate_sav, CONF_BACKUP_EXT); /* Move current configuration file to backup config file. */ - unlink(integrate_sav); - rename(fbackup, integrate_sav); + if (unlink(integrate_sav) != 0) { + vty_out(vty, "Warning: %s unlink failed\n", integrate_sav); + } + if (rename(fbackup, integrate_sav) != 0) { + vty_out(vty, "Error renaming %s to %s\n", fbackup, + integrate_sav); + } free(integrate_sav); } @@ -3760,8 +3748,6 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &no_vtysh_log_monitor_cmd); install_element(CONFIG_NODE, &vtysh_log_syslog_cmd); install_element(CONFIG_NODE, &no_vtysh_log_syslog_cmd); - install_element(CONFIG_NODE, &vtysh_log_trap_cmd); - install_element(CONFIG_NODE, &no_vtysh_log_trap_cmd); install_element(CONFIG_NODE, &vtysh_log_facility_cmd); install_element(CONFIG_NODE, &no_vtysh_log_facility_cmd); install_element(CONFIG_NODE, &vtysh_log_record_priority_cmd); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index e6d324ab6a..5c84219418 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -586,8 +586,13 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); - if (len < 0) + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size: %d %zu", + __PRETTY_FUNCTION__, + h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg))); return -1; + } /* We are interested in some AF_BRIDGE notifications. */ if (ifi->ifi_family == AF_BRIDGE) @@ -893,8 +898,13 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - if (len < 0) + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size: %d %zu", + __PRETTY_FUNCTION__, + h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct ifaddrmsg))); return -1; + } memset(tb, 0, sizeof tb); netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); @@ -1105,8 +1115,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) } len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg)); - if (len < 0) + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size %d %zu", + __PRETTY_FUNCTION__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct ifinfomsg))); return -1; + } /* We are interested in some AF_BRIDGE notifications. */ if (ifi->ifi_family == AF_BRIDGE) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 0e79b82533..d9c6631845 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -498,6 +498,75 @@ const char *nl_rttype_to_str(uint8_t rttype) return lookup_msg(rttype_str, rttype, ""); } +#define NL_OK(nla, len) \ + ((len) >= (int)sizeof(struct nlattr) \ + && (nla)->nla_len >= sizeof(struct nlattr) \ + && (nla)->nla_len <= (len)) +#define NL_NEXT(nla, attrlen) \ + ((attrlen) -= RTA_ALIGN((nla)->nla_len), \ + (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len))) +#define NL_RTA(r) \ + ((struct nlattr *)(((char *)(r)) \ + + NLMSG_ALIGN(sizeof(struct nlmsgerr)))) + +static void netlink_parse_nlattr(struct nlattr **tb, int max, + struct nlattr *nla, int len) +{ + while (NL_OK(nla, len)) { + if (nla->nla_type <= max) + tb[nla->nla_type] = nla; + nla = NL_NEXT(nla, len); + } +} + +static void netlink_parse_extended_ack(struct nlmsghdr *h) +{ + struct nlattr *tb[NLMSGERR_ATTR_MAX + 1]; + const struct nlmsgerr *err = + (const struct nlmsgerr *)((uint8_t *)h + + NLMSG_ALIGN( + sizeof(struct nlmsghdr))); + const struct nlmsghdr *err_nlh = NULL; + uint32_t hlen = sizeof(*err); + const char *msg = NULL; + uint32_t off = 0; + + if (!(h->nlmsg_flags & NLM_F_CAPPED)) + hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr)); + + memset(tb, 0, sizeof(tb)); + netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen); + + if (tb[NLMSGERR_ATTR_MSG]) + msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]); + + if (tb[NLMSGERR_ATTR_OFFS]) { + off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]); + + if (off > h->nlmsg_len) { + zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n"); + } else if (!(h->nlmsg_flags & NLM_F_CAPPED)) { + /* + * Header of failed message + * we are not doing anything currently with it + * but noticing it for later. + */ + err_nlh = &err->msg; + zlog_warn("%s: Received %d extended Ack", + __PRETTY_FUNCTION__, err_nlh->nlmsg_type); + } + } + + if (msg && *msg != '\0') { + bool is_err = !!err->error; + + if (is_err) + zlog_err("Extended Error: %s", msg); + else + zlog_warn("Extended Warning: %s", msg); + } +} + /* * netlink_parse_info * @@ -582,6 +651,23 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), int errnum = err->error; int msg_type = err->msg.nlmsg_type; + if (h->nlmsg_len + < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { + zlog_err("%s error: message truncated", + nl->name); + return -1; + } + + /* + * Parse the extended information before + * we actually handle it. + * At this point in time we do not + * do anything other than report the + * issue. + */ + if (h->nlmsg_flags & NLM_F_ACK_TLVS) + netlink_parse_extended_ack(h); + /* If the error field is zero, then this is an * ACK */ if (err->error == 0) { @@ -603,13 +689,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), continue; } - if (h->nlmsg_len - < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { - zlog_err("%s error: message truncated", - nl->name); - return -1; - } - /* Deal with errors that occur because of races * in link handling */ if (nl == &zns->netlink_cmd @@ -692,6 +771,7 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), error = (*filter)(h, zns->ns_id, startup); if (error < 0) { zlog_err("%s filter function error", nl->name); + zlog_backtrace(LOG_ERR); ret = error; } } @@ -836,6 +916,9 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n) void kernel_init(struct zebra_ns *zns) { unsigned long groups; +#if defined SOL_NETLINK + int one, ret; +#endif /* * Initialize netlink sockets @@ -866,6 +949,25 @@ void kernel_init(struct zebra_ns *zns) zns->netlink_cmd.sock = -1; netlink_socket(&zns->netlink_cmd, 0, zns->ns_id); + /* + * SOL_NETLINK is not available on all platforms yet + * apparently. It's in bits/socket.h which I am not + * sure that we want to pull into our build system. + */ +#if defined SOL_NETLINK + /* + * Let's tell the kernel that we want to receive extended + * ACKS over our command socket + */ + one = 1; + ret = setsockopt(zns->netlink_cmd.sock, SOL_NETLINK, NETLINK_EXT_ACK, + &one, sizeof(one)); + + if (ret < 0) + zlog_notice("Registration for extended ACK failed : %d %s", + errno, safe_strerror(errno)); +#endif + /* Register kernel socket. */ if (zns->netlink.sock > 0) { /* Only want non-blocking on the netlink event socket */ @@ -880,6 +982,7 @@ void kernel_init(struct zebra_ns *zns) netlink_install_filter(zns->netlink.sock, zns->netlink_cmd.snl.nl_pid); zns->t_netlink = NULL; + thread_add_read(zebrad.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a5f288f541..9033491549 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -295,8 +295,12 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, } len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); - if (len < 0) + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size %d %zu", + __PRETTY_FUNCTION__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct rtmsg))); return -1; + } memset(tb, 0, sizeof tb); netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len); @@ -747,8 +751,13 @@ int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); - if (len < 0) + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size: %d %zu", + __PRETTY_FUNCTION__, + h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct rtmsg))); return -1; + } if (rtm->rtm_type == RTN_MULTICAST) netlink_route_change_read_multicast(h, ns_id, startup); @@ -2356,8 +2365,12 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) /* Length validity. */ len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg)); - if (len < 0) + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size %d %zu", + __PRETTY_FUNCTION__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct ndmsg))); return -1; + } /* Is this a notification for the MAC FDB or IP neighbor table? */ ndm = NLMSG_DATA(h); diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index bcffdf4722..c7a8517e17 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -196,8 +196,12 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct fib_rule_hdr)); - if (len < 0) + if (len < 0) { + zlog_err("%s: Message received from netlink is of a broken size: %d %zu", + __PRETTY_FUNCTION__, h->nlmsg_len, + (size_t)NLMSG_LENGTH(sizeof(struct fib_rule_hdr))); return -1; + } frh = NLMSG_DATA(h); if (frh->family != AF_INET && frh->family != AF_INET6) diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index bb6a565211..d0ea661403 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -212,11 +212,18 @@ static int zebra_ns_notify_read(struct thread *t) continue; if (event->mask & IN_DELETE) return zebra_ns_delete(event->name); - if (&event->name[event->len] >= &buf[sizeof(buf)]) { + + if (offsetof(struct inotify_event, name) + event->len + >= sizeof(buf)) { zlog_err("NS notify read: buffer underflow"); break; } - event->name[event->len] = 0; + + if (strnlen(event->name, event->len) == event->len) { + zlog_err("NS notify error: bad event name"); + break; + } + netnspath = ns_netns_pathname(NULL, event->name); if (!netnspath) continue; |
