diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2016-11-08 19:27:58 +0100 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2016-11-08 19:27:58 +0100 |
commit | 8860e991f6650e47cfe6c1af595fe4fe92a4edfd (patch) | |
tree | 18f49bb3a21739a1a596b54d9f65e82cff4fc09f /proto | |
parent | cc5b93f72db80abd1262a0a5e1d8400ceef54385 (diff) | |
parent | c8cafc8ebb5320ac7c6117c17e6460036f0fdf62 (diff) |
Merge branch 'master' into int-new
Diffstat (limited to 'proto')
-rw-r--r-- | proto/babel/babel.c | 4 | ||||
-rw-r--r-- | proto/babel/babel.h | 2 | ||||
-rw-r--r-- | proto/babel/packets.c | 84 | ||||
-rw-r--r-- | proto/bfd/bfd.c | 8 | ||||
-rw-r--r-- | proto/bfd/bfd.h | 19 | ||||
-rw-r--r-- | proto/bfd/config.Y | 46 | ||||
-rw-r--r-- | proto/bfd/packets.c | 249 | ||||
-rw-r--r-- | proto/bgp/attrs.c | 44 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 2 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 5 | ||||
-rw-r--r-- | proto/bgp/config.Y | 4 | ||||
-rw-r--r-- | proto/bgp/packets.c | 29 | ||||
-rw-r--r-- | proto/ospf/config.Y | 14 | ||||
-rw-r--r-- | proto/ospf/hello.c | 7 | ||||
-rw-r--r-- | proto/ospf/iface.c | 28 | ||||
-rw-r--r-- | proto/ospf/lsalib.c | 2 | ||||
-rw-r--r-- | proto/ospf/lsupd.c | 8 | ||||
-rw-r--r-- | proto/ospf/ospf.h | 23 | ||||
-rw-r--r-- | proto/ospf/packet.c | 115 | ||||
-rw-r--r-- | proto/ospf/rt.c | 4 | ||||
-rw-r--r-- | proto/ospf/topology.c | 5 | ||||
-rw-r--r-- | proto/pipe/pipe.c | 2 | ||||
-rw-r--r-- | proto/radv/packets.c | 6 | ||||
-rw-r--r-- | proto/radv/radv.c | 2 | ||||
-rw-r--r-- | proto/rip/config.Y | 24 | ||||
-rw-r--r-- | proto/rip/packets.c | 77 | ||||
-rw-r--r-- | proto/rip/rip.c | 11 | ||||
-rw-r--r-- | proto/rip/rip.h | 2 | ||||
-rw-r--r-- | proto/static/static.c | 4 |
29 files changed, 605 insertions, 225 deletions
diff --git a/proto/babel/babel.c b/proto/babel/babel.c index 9d73a264..38be6909 100644 --- a/proto/babel/babel.c +++ b/proto/babel/babel.c @@ -1723,7 +1723,7 @@ babel_dump(struct proto *P) } static void -babel_get_route_info(rte *rte, byte *buf, ea_list *attrs) +babel_get_route_info(rte *rte, byte *buf, ea_list *attrs UNUSED) { buf += bsprintf(buf, " (%d/%d) [%lR]", rte->pref, rte->u.babel.metric, rte->u.babel.router_id); } @@ -1965,7 +1965,7 @@ babel_store_tmp_attrs(struct rte *rt, struct ea_list *attrs) */ static void babel_rt_notify(struct proto *P, struct rtable *table UNUSED, struct network *net, - struct rte *new, struct rte *old, struct ea_list *attrs) + struct rte *new, struct rte *old UNUSED, struct ea_list *attrs UNUSED) { struct babel_proto *p = (void *) P; struct babel_entry *e; diff --git a/proto/babel/babel.h b/proto/babel/babel.h index 481c88a7..6a95d82f 100644 --- a/proto/babel/babel.h +++ b/proto/babel/babel.h @@ -111,7 +111,7 @@ struct babel_iface_config { u16 rxcost; u8 type; u8 check_link; - int port; + uint port; u16 hello_interval; u16 ihu_interval; u16 update_interval; diff --git a/proto/babel/packets.c b/proto/babel/packets.c index 65dd6853..08054832 100644 --- a/proto/babel/packets.c +++ b/proto/babel/packets.c @@ -146,6 +146,7 @@ struct babel_write_state { #define TLV_HDR(tlv,t,l) ({ tlv->type = t; tlv->length = l - sizeof(struct babel_tlv); }) #define TLV_HDR0(tlv,t) TLV_HDR(tlv, t, tlv_data[t].min_length) +#define BYTES(n) ((((uint) n) + 7) / 8) static inline u16 get_time16(const void *p) @@ -161,18 +162,18 @@ put_time16(void *p, u16 v) } static inline ip6_addr -get_ip6_px(const void *p, int plen) +get_ip6_px(const void *p, uint plen) { ip6_addr addr = IPA_NONE; - memcpy(&addr, p, (plen + 7) / 8); + memcpy(&addr, p, BYTES(plen)); return ip6_ntoh(addr); } static inline void -put_ip6_px(void *p, ip6_addr addr, int plen) +put_ip6_px(void *p, ip6_addr addr, uint plen) { addr = ip6_hton(addr); - memcpy(p, &addr, (plen + 7) / 8); + memcpy(p, &addr, BYTES(plen)); } static inline ip6_addr @@ -202,21 +203,21 @@ static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); -static int babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, int max_len); -static int babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, int max_len); -static int babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, int max_len); -static int babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, int max_len); -static int babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, int max_len); -static int babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, int max_len); +static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); +static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); +static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); +static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); +static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); +static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); struct babel_tlv_data { u8 min_length; int (*read_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_parse_state *state); - int (*write_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_write_state *state, int max_len); + uint (*write_tlv)(struct babel_tlv *hdr, union babel_msg *m, struct babel_write_state *state, uint max_len); void (*handle_tlv)(union babel_msg *m, struct babel_iface *ifa); }; -const static struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = { +static const struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = { [BABEL_TLV_ACK_REQ] = { sizeof(struct babel_tlv_ack_req), babel_read_ack_req, @@ -291,9 +292,9 @@ babel_read_ack_req(struct babel_tlv *hdr, union babel_msg *m, return PARSE_SUCCESS; } -static int +static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *m, - struct babel_write_state *state, int max_len) + struct babel_write_state *state UNUSED, uint max_len UNUSED) { struct babel_tlv_ack *tlv = (void *) hdr; struct babel_msg_ack *msg = &m->ack; @@ -319,9 +320,9 @@ babel_read_hello(struct babel_tlv *hdr, union babel_msg *m, return PARSE_SUCCESS; } -static int +static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *m, - struct babel_write_state *state, int max_len) + struct babel_write_state *state UNUSED, uint max_len UNUSED) { struct babel_tlv_hello *tlv = (void *) hdr; struct babel_msg_hello *msg = &m->hello; @@ -363,9 +364,9 @@ babel_read_ihu(struct babel_tlv *hdr, union babel_msg *m, return PARSE_SUCCESS; } -static int +static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *m, - struct babel_write_state *state, int max_len) + struct babel_write_state *state UNUSED, uint max_len) { struct babel_tlv_ihu *tlv = (void *) hdr; struct babel_msg_ihu *msg = &m->ihu; @@ -401,9 +402,9 @@ babel_read_router_id(struct babel_tlv *hdr, union babel_msg *m UNUSED, } /* This is called directly from babel_write_update() */ -static int +static uint babel_write_router_id(struct babel_tlv *hdr, u64 router_id, - struct babel_write_state *state, int max_len UNUSED) + struct babel_write_state *state, uint max_len UNUSED) { struct babel_tlv_router_id *tlv = (void *) hdr; @@ -467,10 +468,10 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, msg->metric = get_u16(&tlv->metric); /* Length of received prefix data without omitted part */ - int len = (tlv->plen + 7)/8 - (int) tlv->omitted; + int len = BYTES(tlv->plen) - (int) tlv->omitted; u8 buf[16] = {}; - if ((len < 0) || (len > TLV_OPT_LENGTH(tlv))) + if ((len < 0) || ((uint) len > TLV_OPT_LENGTH(tlv))) return PARSE_ERROR; switch (tlv->ae) @@ -536,13 +537,13 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m, return PARSE_SUCCESS; } -static int +static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *m, - struct babel_write_state *state, int max_len) + struct babel_write_state *state, uint max_len) { struct babel_tlv_update *tlv = (void *) hdr; struct babel_msg_update *msg = &m->update; - int len0 = 0; + uint len0 = 0; /* * When needed, we write Router-ID TLV before Update TLV and return size of @@ -558,7 +559,7 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m, tlv = (struct babel_tlv_update *) NEXT_TLV(tlv); } - int len = sizeof(struct babel_tlv_update) + (msg->plen + 7)/8; + uint len = sizeof(struct babel_tlv_update) + BYTES(msg->plen); if (len0 + len > max_len) return 0; @@ -587,7 +588,7 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m, static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, - struct babel_parse_state *state) + struct babel_parse_state *state UNUSED) { struct babel_tlv_route_request *tlv = (void *) hdr; struct babel_msg_route_request *msg = &m->route_request; @@ -612,7 +613,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, if (tlv->plen > MAX_PREFIX_LENGTH) return PARSE_ERROR; - if (TLV_OPT_LENGTH(tlv) < (tlv->plen + 7)/8) + if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen)) return PARSE_ERROR; msg->plen = tlv->plen; @@ -629,14 +630,14 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_IGNORE; } -static int +static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m, - struct babel_write_state *state, int max_len) + struct babel_write_state *state UNUSED, uint max_len) { struct babel_tlv_route_request *tlv = (void *) hdr; struct babel_msg_route_request *msg = &m->route_request; - int len = sizeof(struct babel_tlv_route_request) + (msg->plen + 7)/8; + uint len = sizeof(struct babel_tlv_route_request) + BYTES(msg->plen); if (len > max_len) return 0; @@ -687,7 +688,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, if (tlv->plen > MAX_PREFIX_LENGTH) return PARSE_ERROR; - if (TLV_OPT_LENGTH(tlv) < (tlv->plen + 7)/8) + if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen)) return PARSE_ERROR; msg->plen = tlv->plen; @@ -704,14 +705,14 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m, return PARSE_IGNORE; } -static int +static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m, - struct babel_write_state *state, int max_len) + struct babel_write_state *state UNUSED, uint max_len) { struct babel_tlv_seqno_request *tlv = (void *) hdr; struct babel_msg_seqno_request *msg = &m->seqno_request; - int len = sizeof(struct babel_tlv_seqno_request) + (msg->plen + 7)/8; + uint len = sizeof(struct babel_tlv_seqno_request) + BYTES(msg->plen); if (len > max_len) return 0; @@ -744,11 +745,11 @@ babel_read_tlv(struct babel_tlv *hdr, return tlv_data[hdr->type].read_tlv(hdr, msg, state); } -static int +static uint babel_write_tlv(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, - int max_len) + uint max_len) { if ((msg->type <= BABEL_TLV_PADN) || (msg->type >= BABEL_TLV_MAX) || @@ -792,7 +793,7 @@ babel_send_to(struct babel_iface *ifa, ip_addr dest) * * The TLVs in the queue are freed after they are written to the buffer. */ -static int +static uint babel_write_queue(struct babel_iface *ifa, list *queue) { struct babel_proto *p = ifa->proto; @@ -813,6 +814,9 @@ babel_write_queue(struct babel_iface *ifa, list *queue) struct babel_msg_node *msg; WALK_LIST_FIRST(msg, *queue) { + if (pos >= end) + break; + int len = babel_write_tlv((struct babel_tlv *) pos, &msg->msg, &state, end - pos); if (!len) @@ -823,7 +827,7 @@ babel_write_queue(struct babel_iface *ifa, list *queue) sl_free(p->msg_slab, msg); } - int plen = pos - (byte *) pkt; + uint plen = pos - (byte *) pkt; put_u16(&pkt->length, plen - sizeof(struct babel_pkt_header)); return plen; @@ -1027,7 +1031,7 @@ babel_tx_hook(sock *sk) static int -babel_rx_hook(sock *sk, int len) +babel_rx_hook(sock *sk, uint len) { struct babel_iface *ifa = sk->data; struct babel_proto *p = ifa->proto; diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index d33424b0..e2c6050b 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -316,6 +316,7 @@ bfd_session_timeout(struct bfd_session *s) s->rem_min_rx_int = 1; s->rem_demand_mode = 0; s->rem_detect_mult = 0; + s->rx_csn_known = 0; s->poll_active = 0; s->poll_scheduled = 0; @@ -429,6 +430,7 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface * s->rem_min_rx_int = 1; s->detect_mult = ifa->cf->multiplier; s->passive = ifa->cf->passive; + s->tx_csn = random_u32(); s->tx_timer = tm2_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0); s->hold_timer = tm2_new_init(p->tpool, bfd_hold_timer_hook, s, 0, 0); @@ -796,7 +798,7 @@ bfd_start_neighbor(struct bfd_proto *p, struct bfd_neighbor *n) } static void -bfd_stop_neighbor(struct bfd_proto *p, struct bfd_neighbor *n) +bfd_stop_neighbor(struct bfd_proto *p UNUSED, struct bfd_neighbor *n) { if (n->neigh) n->neigh->data = NULL; @@ -853,7 +855,7 @@ void pipe_drain(int fd); void pipe_kick(int fd); static int -bfd_notify_hook(sock *sk, int len) +bfd_notify_hook(sock *sk, uint len UNUSED) { struct bfd_proto *p = sk->data; struct bfd_session *s; @@ -1062,7 +1064,7 @@ bfd_preconfig(struct protocol *P UNUSED, struct config *c UNUSED) } static void -bfd_copy_config(struct proto_config *dest, struct proto_config *src) +bfd_copy_config(struct proto_config *dest, struct proto_config *src UNUSED) { struct bfd_config *d = (struct bfd_config *) dest; // struct bfd_config *s = (struct bfd_config *) src; diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h index ce7d665b..e2e75753 100644 --- a/proto/bfd/bfd.h +++ b/proto/bfd/bfd.h @@ -14,6 +14,7 @@ #include "nest/iface.h" #include "nest/protocol.h" #include "nest/route.h" +#include "nest/password.h" #include "conf/conf.h" #include "lib/hash.h" #include "lib/resource.h" @@ -52,6 +53,8 @@ struct bfd_iface_config u32 idle_tx_int; u8 multiplier; u8 passive; + u8 auth_type; /* Authentication type (BFD_AUTH_*) */ + list *passwords; /* Passwords for authentication */ }; struct bfd_neighbor @@ -116,7 +119,7 @@ struct bfd_session u8 passive; u8 poll_active; u8 poll_scheduled; - + u8 loc_state; u8 rem_state; u8 loc_diag; @@ -143,6 +146,11 @@ struct bfd_session list request_list; /* List of client requests (struct bfd_request) */ bird_clock_t last_state_change; /* Time of last state change */ u8 notify_running; /* 1 if notify hooks are running */ + + u8 rx_csn_known; /* Received crypto sequence number is known */ + u32 rx_csn; /* Last received crypto sequence number */ + u32 tx_csn; /* Last transmitted crypto sequence number */ + u32 tx_csn_time; /* Timestamp of last tx_csn change */ }; @@ -174,6 +182,15 @@ extern const char *bfd_state_names[]; #define BFD_FLAG_DEMAND (1 << 1) #define BFD_FLAG_MULTIPOINT (1 << 0) +#define BFD_AUTH_NONE 0 +#define BFD_AUTH_SIMPLE 1 +#define BFD_AUTH_KEYED_MD5 2 +#define BFD_AUTH_METICULOUS_KEYED_MD5 3 +#define BFD_AUTH_KEYED_SHA1 4 +#define BFD_AUTH_METICULOUS_KEYED_SHA1 5 + +extern const u8 bfd_auth_type_to_hash_alg[]; + static inline void bfd_lock_sessions(struct bfd_proto *p) { pthread_spin_lock(&p->lock); } static inline void bfd_unlock_sessions(struct bfd_proto *p) { pthread_spin_unlock(&p->lock); } diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y index 4affb927..73414362 100644 --- a/proto/bfd/config.Y +++ b/proto/bfd/config.Y @@ -22,11 +22,12 @@ extern struct bfd_config *bfd_cf; CF_DECLS CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE, - INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL) + INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION, + NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1) %type <iface> bfd_neigh_iface %type <a> bfd_neigh_local -%type <i> bfd_neigh_multihop +%type <i> bfd_neigh_multihop bfd_auth_type CF_GRAMMAR @@ -62,12 +63,35 @@ bfd_proto: bfd_iface_start: { this_ipatt = cfg_allocz(sizeof(struct bfd_iface_config)); + add_tail(&BFD_CFG->patt_list, NODE this_ipatt); init_list(&this_ipatt->ipn_list); BFD_IFACE->min_rx_int = BFD_DEFAULT_MIN_RX_INT; BFD_IFACE->min_tx_int = BFD_DEFAULT_MIN_TX_INT; BFD_IFACE->idle_tx_int = BFD_DEFAULT_IDLE_TX_INT; BFD_IFACE->multiplier = BFD_DEFAULT_MULTIPLIER; + + reset_passwords(); +}; + +bfd_iface_finish: +{ + BFD_IFACE->passwords = get_passwords(); + + if (!BFD_IFACE->auth_type != !BFD_IFACE->passwords) + log(L_WARN "Authentication and password options should be used together"); + + if (BFD_IFACE->passwords) + { + struct password_item *pass; + WALK_LIST(pass, *BFD_IFACE->passwords) + { + if (pass->alg) + cf_error("Password algorithm option not available in BFD protocol"); + + pass->alg = bfd_auth_type_to_hash_alg[BFD_IFACE->auth_type]; + } + } }; bfd_iface_item: @@ -77,6 +101,17 @@ bfd_iface_item: | IDLE TX INTERVAL expr_us { BFD_IFACE->idle_tx_int = $4; } | MULTIPLIER expr { BFD_IFACE->multiplier = $2; } | PASSIVE bool { BFD_IFACE->passive = $2; } + | AUTHENTICATION bfd_auth_type { BFD_IFACE->auth_type = $2; } + | password_list {} + ; + +bfd_auth_type: + NONE { $$ = BFD_AUTH_NONE; } + | SIMPLE { $$ = BFD_AUTH_SIMPLE; } + | KEYED MD5 { $$ = BFD_AUTH_KEYED_MD5; } + | KEYED SHA1 { $$ = BFD_AUTH_KEYED_SHA1; } + | METICULOUS KEYED MD5 { $$ = BFD_AUTH_METICULOUS_KEYED_MD5; } + | METICULOUS KEYED SHA1 { $$ = BFD_AUTH_METICULOUS_KEYED_SHA1; } ; bfd_iface_opts: @@ -89,10 +124,11 @@ bfd_iface_opt_list: | '{' bfd_iface_opts '}' ; -bfd_iface: bfd_iface_start iface_patt_list_nopx bfd_iface_opt_list -{ add_tail(&BFD_CFG->patt_list, NODE this_ipatt); }; +bfd_iface: + bfd_iface_start iface_patt_list_nopx bfd_iface_opt_list bfd_iface_finish; -bfd_multihop: bfd_iface_start bfd_iface_opt_list +bfd_multihop: + bfd_iface_start bfd_iface_opt_list bfd_iface_finish { BFD_CFG->multihop = BFD_IFACE; }; diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c index 579064c6..06cde4d3 100644 --- a/proto/bfd/packets.c +++ b/proto/bfd/packets.c @@ -5,24 +5,60 @@ */ #include "bfd.h" +#include "lib/mac.h" struct bfd_ctl_packet { - u8 vdiag; /* version and diagnostic */ - u8 flags; /* state and flags */ + u8 vdiag; /* Version and diagnostic */ + u8 flags; /* State and flags */ u8 detect_mult; - u8 length; - u32 snd_id; /* sender ID, aka 'my discriminator' */ - u32 rcv_id; /* receiver ID, aka 'your discriminator' */ + u8 length; /* Whole packet length */ + u32 snd_id; /* Sender ID, aka 'my discriminator' */ + u32 rcv_id; /* Receiver ID, aka 'your discriminator' */ u32 des_min_tx_int; u32 req_min_rx_int; u32 req_min_echo_rx_int; }; +struct bfd_auth +{ + u8 type; /* Authentication type (BFD_AUTH_*) */ + u8 length; /* Authentication section length */ +}; + +struct bfd_simple_auth +{ + u8 type; /* BFD_AUTH_SIMPLE */ + u8 length; /* Length of bfd_simple_auth + pasword length */ + u8 key_id; /* Key ID */ + byte password[0]; /* Password itself, variable length */ +}; + +#define BFD_MAX_PASSWORD_LENGTH 16 + +struct bfd_crypto_auth +{ + u8 type; /* BFD_AUTH_*_MD5 or BFD_AUTH_*_SHA1 */ + u8 length; /* Length of bfd_crypto_auth + hash length */ + u8 key_id; /* Key ID */ + u8 zero; /* Reserved, zero on transmit */ + u32 csn; /* Cryptographic sequence number */ + byte data[0]; /* Authentication key/hash, length 16 or 20 */ +}; + #define BFD_BASE_LEN sizeof(struct bfd_ctl_packet) #define BFD_MAX_LEN 64 +#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0) + +#define LOG_PKT(msg, args...) \ + log(L_REMOTE "%s: " msg, p->p.name, args) + +#define LOG_PKT_AUTH(msg, args...) \ + log(L_AUTH "%s: " msg, p->p.name, args) + + static inline u8 bfd_pack_vdiag(u8 version, u8 diag) { return (version << 5) | diag; } @@ -39,7 +75,7 @@ static inline u8 bfd_pkt_get_diag(struct bfd_ctl_packet *pkt) static inline u8 bfd_pkt_get_state(struct bfd_ctl_packet *pkt) { return pkt->flags >> 6; } -static inline void bfd_pkt_set_state(struct bfd_ctl_packet *pkt, u8 val) +static inline void UNUSED bfd_pkt_set_state(struct bfd_ctl_packet *pkt, u8 val) { pkt->flags = val << 6; } @@ -59,6 +95,189 @@ bfd_format_flags(u8 flags, char *buf) return buf; } +const u8 bfd_auth_type_to_hash_alg[] = { + [BFD_AUTH_NONE] = ALG_UNDEFINED, + [BFD_AUTH_SIMPLE] = ALG_UNDEFINED, + [BFD_AUTH_KEYED_MD5] = ALG_MD5, + [BFD_AUTH_METICULOUS_KEYED_MD5] = ALG_MD5, + [BFD_AUTH_KEYED_SHA1] = ALG_SHA1, + [BFD_AUTH_METICULOUS_KEYED_SHA1] = ALG_SHA1, +}; + + +/* Fill authentication section and modifies final length in control section packet */ +static void +bfd_fill_authentication(struct bfd_proto *p, struct bfd_session *s, struct bfd_ctl_packet *pkt) +{ + struct bfd_iface_config *cf = s->ifa->cf; + struct password_item *pass = password_find(cf->passwords, 0); + uint meticulous = 0; + + if (!pass) + { + /* FIXME: This should not happen */ + log(L_ERR "%s: No suitable password found for authentication", p->p.name); + return; + } + + switch (cf->auth_type) + { + case BFD_AUTH_SIMPLE: + { + struct bfd_simple_auth *auth = (void *) (pkt + 1); + uint pass_len = MIN(pass->length, BFD_MAX_PASSWORD_LENGTH); + + auth->type = BFD_AUTH_SIMPLE; + auth->length = sizeof(struct bfd_simple_auth) + pass_len; + auth->key_id = pass->id; + + pkt->flags |= BFD_FLAG_AP; + pkt->length += auth->length; + + memcpy(auth->password, pass->password, pass_len); + return; + } + + case BFD_AUTH_METICULOUS_KEYED_MD5: + case BFD_AUTH_METICULOUS_KEYED_SHA1: + meticulous = 1; + + case BFD_AUTH_KEYED_MD5: + case BFD_AUTH_KEYED_SHA1: + { + struct bfd_crypto_auth *auth = (void *) (pkt + 1); + uint hash_alg = bfd_auth_type_to_hash_alg[cf->auth_type]; + uint hash_len = mac_type_length(pass->alg); + + /* Increase CSN about one time per second */ + u32 new_time = (u64) current_time() >> 20; + if ((new_time != s->tx_csn_time) || meticulous) + { + s->tx_csn++; + s->tx_csn_time = new_time; + } + + DBG("[%I] CSN: %u\n", s->addr, s->last_tx_csn); + + auth->type = cf->auth_type; + auth->length = sizeof(struct bfd_crypto_auth) + hash_len; + auth->key_id = pass->id; + auth->zero = 0; + auth->csn = htonl(s->tx_csn); + + pkt->flags |= BFD_FLAG_AP; + pkt->length += auth->length; + + strncpy(auth->data, pass->password, hash_len); + mac_fill(hash_alg, NULL, 0, (byte *) pkt, pkt->length, auth->data); + return; + } + } +} + +static int +bfd_check_authentication(struct bfd_proto *p, struct bfd_session *s, struct bfd_ctl_packet *pkt) +{ + struct bfd_iface_config *cf = s->ifa->cf; + const char *err_dsc = NULL; + uint err_val = 0; + uint auth_type = 0; + uint meticulous = 0; + + if (pkt->flags & BFD_FLAG_AP) + { + struct bfd_auth *auth = (void *) (pkt + 1); + + if ((pkt->length < (BFD_BASE_LEN + sizeof(struct bfd_auth))) || + (pkt->length < (BFD_BASE_LEN + auth->length))) + DROP("packet length mismatch", pkt->length); + + /* Zero is reserved, we use it as BFD_AUTH_NONE internally */ + if (auth->type == 0) + DROP("reserved authentication type", 0); + + auth_type = auth->type; + } + + if (auth_type != cf->auth_type) + DROP("authentication method mismatch", auth_type); + + switch (auth_type) + { + case BFD_AUTH_NONE: + return 1; + + case BFD_AUTH_SIMPLE: + { + struct bfd_simple_auth *auth = (void *) (pkt + 1); + + if (auth->length < sizeof(struct bfd_simple_auth)) + DROP("wrong authentication length", auth->length); + + struct password_item *pass = password_find_by_id(cf->passwords, auth->key_id); + if (!pass) + DROP("no suitable password found", auth->key_id); + + uint pass_len = MIN(pass->length, BFD_MAX_PASSWORD_LENGTH); + uint auth_len = sizeof(struct bfd_simple_auth) + pass_len; + + if ((auth->length != auth_len) || memcmp(auth->password, pass->password, pass_len)) + DROP("wrong password", pass->id); + + return 1; + } + + case BFD_AUTH_METICULOUS_KEYED_MD5: + case BFD_AUTH_METICULOUS_KEYED_SHA1: + meticulous = 1; + + case BFD_AUTH_KEYED_MD5: + case BFD_AUTH_KEYED_SHA1: + { + struct bfd_crypto_auth *auth = (void *) (pkt + 1); + uint hash_alg = bfd_auth_type_to_hash_alg[cf->auth_type]; + uint hash_len = mac_type_length(hash_alg); + + if (auth->length != (sizeof(struct bfd_crypto_auth) + hash_len)) + DROP("wrong authentication length", auth->length); + + struct password_item *pass = password_find_by_id(cf->passwords, auth->key_id); + if (!pass) + DROP("no suitable password found", auth->key_id); + + /* BFD CSNs are in 32-bit circular number space */ + u32 csn = ntohl(auth->csn); + if (s->rx_csn_known && + (((csn - s->rx_csn) > (3 * s->detect_mult)) || + (meticulous && (csn == s->rx_csn)))) + { + /* We want to report both new and old CSN */ + LOG_PKT_AUTH("Authentication failed for %I - " + "wrong sequence number (rcv %u, old %u)", + s->addr, csn, s->rx_csn); + return 0; + } + + byte *auth_data = alloca(hash_len); + memcpy(auth_data, auth->data, hash_len); + strncpy(auth->data, pass->password, hash_len); + + if (!mac_verify(hash_alg, NULL, 0, (byte *) pkt, pkt->length, auth_data)) + DROP("wrong authentication code", pass->id); + + s->rx_csn = csn; + s->rx_csn_known = 1; + + return 1; + } + } + +drop: + LOG_PKT_AUTH("Authentication failed for %I - %s (%u)", + s->addr, err_dsc, err_val); + return 0; +} + void bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final) { @@ -85,6 +304,9 @@ bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final) else if (s->poll_active) pkt->flags |= BFD_FLAG_POLL; + if (s->ifa->cf->auth_type) + bfd_fill_authentication(p, s, pkt); + if (sk->tbuf != sk->tpos) log(L_WARN "%s: Old packet overwritten in TX buffer", p->p.name); @@ -94,10 +316,8 @@ bfd_send_ctl(struct bfd_proto *p, struct bfd_session *s, int final) sk_send_to(sk, pkt->length, s->addr, sk->dport); } -#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0) - static int -bfd_rx_hook(sock *sk, int len) +bfd_rx_hook(sock *sk, uint len) { struct bfd_proto *p = sk->data; struct bfd_ctl_packet *pkt = (struct bfd_ctl_packet *) sk->rbuf; @@ -151,10 +371,9 @@ bfd_rx_hook(sock *sk, int len) return 1; } - /* FIXME: better authentication handling and message */ - if (pkt->flags & BFD_FLAG_AP) - DROP("authentication not supported", 0); - + /* bfd_check_authentication() has its own error logging */ + if (!bfd_check_authentication(p, s, pkt)) + return 1; u32 old_tx_int = s->des_min_tx_int; u32 old_rx_int = s->rem_min_rx_int; @@ -173,8 +392,8 @@ bfd_rx_hook(sock *sk, int len) bfd_session_process_ctl(s, pkt->flags, old_tx_int, old_rx_int); return 1; - drop: - log(L_REMOTE "%s: Bad packet from %I - %s (%u)", p->p.name, sk->faddr, err_dsc, err_val); +drop: + LOG_PKT("Bad packet from %I - %s (%u)", sk->faddr, err_dsc, err_val); return 1; } diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c index b8371f32..0309c1f7 100644 --- a/proto/bgp/attrs.c +++ b/proto/bgp/attrs.c @@ -191,7 +191,7 @@ validate_as4_path(struct bgp_proto *p, struct adata *path) } static int -bgp_check_next_hop(struct bgp_proto *p UNUSED, byte *a, int len) +bgp_check_next_hop(struct bgp_proto *p UNUSED, byte *a UNUSED6, int len UNUSED6) { #ifdef IPV6 return IGNORE; @@ -289,6 +289,12 @@ bgp_check_ext_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len) return ((len % 8) == 0) ? 0 : WITHDRAW; } +static int +bgp_check_large_community(struct bgp_proto *p UNUSED, byte *a UNUSED, int len) +{ + return ((len % 12) == 0) ? 0 : WITHDRAW; +} + static struct attr_desc bgp_attr_table[] = { { NULL, -1, 0, 0, 0, /* Undefined */ @@ -325,7 +331,10 @@ static struct attr_desc bgp_attr_table[] = { { "as4_path", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AS4_PATH */ NULL, NULL }, { "as4_aggregator", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AS4_PATH */ - NULL, NULL } + NULL, NULL }, + [BA_LARGE_COMMUNITY] = + { "large_community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_LC_SET, 1, + bgp_check_large_community, NULL } }; /* BA_AS4_PATH is type EAF_TYPE_OPAQUE and not type EAF_TYPE_AS_PATH. @@ -575,7 +584,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains) len = bgp_get_attr_len(a); /* Skip empty sets */ - if (((type == EAF_TYPE_INT_SET) || (type == EAF_TYPE_EC_SET)) && (len == 0)) + if (((type == EAF_TYPE_INT_SET) || (type == EAF_TYPE_EC_SET) || (type == EAF_TYPE_LC_SET)) && (len == 0)) continue; if (remains < len + 4) @@ -601,6 +610,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains) break; } case EAF_TYPE_INT_SET: + case EAF_TYPE_LC_SET: case EAF_TYPE_EC_SET: { u32 *z = int_set_get_data(a->u.ptr); @@ -683,6 +693,25 @@ bgp_normalize_ec_set(struct adata *ad, u32 *src, int internal) qsort(dst, ad->length / 8, 8, (int(*)(const void *, const void *)) bgp_compare_ec); } +static int +bgp_compare_lc(const u32 *x, const u32 *y) +{ + if (x[0] != y[0]) + return (x[0] > y[0]) ? 1 : -1; + if (x[1] != y[1]) + return (x[1] > y[1]) ? 1 : -1; + if (x[2] != y[2]) + return (x[2] > y[2]) ? 1 : -1; + return 0; +} + +static inline void +bgp_normalize_lc_set(u32 *dest, u32 *src, unsigned cnt) +{ + memcpy(dest, src, LCOMM_LENGTH * cnt); + qsort(dest, cnt, LCOMM_LENGTH, (int(*)(const void *, const void *)) bgp_compare_lc); +} + static void bgp_rehash_buckets(struct bgp_proto *p) { @@ -827,6 +856,14 @@ bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate) d->u.ptr = z; break; } + case EAF_TYPE_LC_SET: + { + struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length); + z->length = d->u.ptr->length; + bgp_normalize_lc_set((u32 *) z->data, (u32 *) d->u.ptr->data, z->length / LCOMM_LENGTH); + d->u.ptr = z; + break; + } default: ; } d++; @@ -1797,6 +1834,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, uint len, struct linpool *po ipa_ntoh(*(ip_addr *)ad->data); break; case EAF_TYPE_INT_SET: + case EAF_TYPE_LC_SET: case EAF_TYPE_EC_SET: { u32 *z = (u32 *) ad->data; diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 0ae3db7b..cac5d4c4 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -807,7 +807,7 @@ bgp_find_proto(sock *sk) * closes the new connection by sending a Notification message. */ static int -bgp_incoming_connection(sock *sk, int dummy UNUSED) +bgp_incoming_connection(sock *sk, uint dummy UNUSED) { struct bgp_proto *p; int acc, hops; diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index b1cca2d9..b4067f3a 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -191,7 +191,7 @@ struct bgp_bucket { #define BGP_RX_BUFFER_EXT_SIZE 65535 #define BGP_TX_BUFFER_EXT_SIZE 65535 -static inline int bgp_max_packet_length(struct bgp_proto *p) +static inline uint bgp_max_packet_length(struct bgp_proto *p) { return p->ext_messages ? BGP_MAX_EXT_MSG_LENGTH : BGP_MAX_MESSAGE_LENGTH; } extern struct linpool *bgp_linpool; @@ -268,7 +268,7 @@ void mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new void bgp_schedule_packet(struct bgp_conn *conn, int type); void bgp_kick_tx(void *vconn); void bgp_tx(struct birdsock *sk); -int bgp_rx(struct birdsock *sk, int size); +int bgp_rx(struct birdsock *sk, uint size); const char * bgp_error_dsc(unsigned code, unsigned subcode); void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len); @@ -308,6 +308,7 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi #define BA_EXT_COMMUNITY 0x10 /* [RFC4360] */ #define BA_AS4_PATH 0x11 /* [RFC4893] */ #define BA_AS4_AGGREGATOR 0x12 +#define BA_LARGE_COMMUNITY 0x20 /* [draft-ietf-idr-large-community] */ /* BGP connection states */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 33561bff..bdbb6007 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -27,7 +27,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE, - CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY) + CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, BGP_LARGE_COMMUNITY) CF_GRAMMAR @@ -153,6 +153,8 @@ CF_ADDTO(dynamic_attr, BGP_CLUSTER_LIST { $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(EAP_BGP, BA_CLUSTER_LIST)); }) CF_ADDTO(dynamic_attr, BGP_EXT_COMMUNITY { $$ = f_new_dynamic_attr(EAF_TYPE_EC_SET, T_ECLIST, EA_CODE(EAP_BGP, BA_EXT_COMMUNITY)); }) +CF_ADDTO(dynamic_attr, BGP_LARGE_COMMUNITY + { $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(EAP_BGP, BA_LARGE_COMMUNITY)); }) diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 0cf38edf..3e816839 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -191,7 +191,7 @@ bgp_put_cap_gr1(struct bgp_proto *p, byte *buf) } static byte * -bgp_put_cap_gr2(struct bgp_proto *p, byte *buf) +bgp_put_cap_gr2(struct bgp_proto *p UNUSED, byte *buf) { *buf++ = 64; /* Capability 64: Support for graceful restart */ *buf++ = 2; /* Capability data length */ @@ -931,7 +931,7 @@ bgp_parse_options(struct bgp_conn *conn, byte *opt, int len) } static void -bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len) +bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len) { struct bgp_conn *other; struct bgp_proto *p = conn->bgp; @@ -944,7 +944,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len) { bgp_error(conn, 5, fsm_err_subcode[conn->state], NULL, 0); return; } /* Check message contents */ - if (len < 29 || len != 29 + pkt[28]) + if (len < 29 || len != 29U + pkt[28]) { bgp_error(conn, 1, 2, pkt+16, 2); return; } if (pkt[19] != BGP_VERSION) { bgp_error(conn, 2, 1, pkt+19, 1); return; } /* RFC 1771 says 16 bits, draft-09 tells to use 8 */ @@ -1256,16 +1256,15 @@ bgp_do_rx_update(struct bgp_conn *conn, #else /* IPv6 version */ #define DO_NLRI(name) \ - start = x = p->name##_start; \ + x = p->name##_start; \ len = len0 = p->name##_len; \ if (len) \ { \ if (len < 3) { err=9; goto done; } \ af = get_u16(x); \ - sub = x[2]; \ x += 3; \ len -= 3; \ - DBG("\tNLRI AF=%d sub=%d len=%d\n", af, sub, len);\ + DBG("\tNLRI AF=%d sub=%d len=%d\n", af, x[-1], len);\ } \ else \ af = 0; \ @@ -1291,15 +1290,15 @@ bgp_attach_next_hop(rta *a0, byte *x) static void bgp_do_rx_update(struct bgp_conn *conn, - byte *withdrawn, int withdrawn_len, - byte *nlri, int nlri_len, + byte *withdrawn UNUSED, int withdrawn_len, + byte *nlri UNUSED, int nlri_len, byte *attrs, int attr_len) { struct bgp_proto *p = conn->bgp; struct rte_src *src = p->p.main_source; - byte *start, *x; + byte *x; int len, len0; - unsigned af, sub; + unsigned af; rta *a0, *a = NULL; ip_addr prefix; int pxlen, err = 0; @@ -1375,11 +1374,11 @@ bgp_do_rx_update(struct bgp_conn *conn, #endif static void -bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len) +bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len) { struct bgp_proto *p = conn->bgp; byte *withdrawn, *attrs, *nlri; - int withdrawn_len, attr_len, nlri_len; + uint withdrawn_len, attr_len, nlri_len; BGP_TRACE_RL(&rl_rcv_update, D_PACKETS, "Got UPDATE"); @@ -1525,7 +1524,7 @@ bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned } static void -bgp_rx_notification(struct bgp_conn *conn, byte *pkt, int len) +bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len) { struct bgp_proto *p = conn->bgp; if (len < 21) @@ -1591,7 +1590,7 @@ bgp_rx_keepalive(struct bgp_conn *conn) } static void -bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, int len) +bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, uint len) { struct bgp_proto *p = conn->bgp; @@ -1680,7 +1679,7 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsigned len) * bgp_rx_packet(). */ int -bgp_rx(sock *sk, int size) +bgp_rx(sock *sk, uint size) { struct bgp_conn *conn = sk->data; struct bgp_proto *p = conn->bgp; diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 297774b5..72928875 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -42,6 +42,20 @@ ospf_iface_finish(void) if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL)) log(L_WARN "Password option without authentication option does not make sense"); + + if (ip->passwords) + { + struct password_item *pass; + WALK_LIST(pass, *ip->passwords) + { + if (pass->alg && (ip->autype != OSPF_AUTH_CRYPT)) + cf_error("Password algorithm option requires cryptographic authentication"); + + /* Set default OSPF crypto algorithms */ + if (!pass->alg && (ip->autype == OSPF_AUTH_CRYPT)) + pass->alg = ospf_cfg_is_v2() ? ALG_MD5 : ALG_HMAC_SHA256; + } + } } static void diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index 3fbb6167..2c55155d 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -105,7 +105,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn) } i = 0; - max = (ospf_pkt_maxsize(p, ifa) - length) / sizeof(u32); + max = (ospf_pkt_maxsize(ifa) - length) / sizeof(u32); /* Fill all neighbors */ if (kind != OHS_SHUTDOWN) @@ -222,9 +222,12 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, rcv_priority = ps->priority; int pxlen = u32_masklen(ntohl(ps->netmask)); + if (pxlen < 0) + DROP("prefix garbled", ntohl(ps->netmask)); + if ((ifa->type != OSPF_IT_VLINK) && (ifa->type != OSPF_IT_PTP) && - (pxlen != ifa->addr->prefix.pxlen)) + ((uint) pxlen != ifa->addr->prefix.pxlen)) DROP("prefix length mismatch", pxlen); neighbors = ps->neighbors; diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 6ef24ffe..675cf76d 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -9,6 +9,7 @@ */ #include "ospf.h" +#include "nest/password.h" const char *ospf_is_names[] = { @@ -52,6 +53,20 @@ ifa_tx_length(struct ospf_iface *ifa) } static inline uint +ifa_tx_hdrlen(struct ospf_iface *ifa) +{ + struct ospf_proto *p = ifa->oa->po; + + uint hlen = ospf_is_v2(p) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH; + + /* Relevant just for OSPFv2 */ + if (ifa->autype == OSPF_AUTH_CRYPT) + hlen += max_mac_length(ifa->passwords); + + return hlen; +} + +static inline uint ifa_bufsize(struct ospf_iface *ifa) { uint bsize = ifa->cf->rx_buffer ?: ifa->iface->mtu; @@ -67,13 +82,7 @@ ifa_flood_queue_size(struct ospf_iface *ifa) int ospf_iface_assure_bufsize(struct ospf_iface *ifa, uint plen) { - struct ospf_proto *p = ifa->oa->po; - - plen += ospf_is_v2(p) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH; - - /* This is relevant just for OSPFv2 */ - if (ifa->autype == OSPF_AUTH_CRYPT) - plen += OSPF_AUTH_CRYPT_SIZE; + plen += ifa->tx_hdrlen; if (plen <= ifa->sk->tbsize) return 0; @@ -569,6 +578,7 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i ifa->stub = ospf_iface_stubby(ip, addr); ifa->ioprob = OSPF_I_OK; ifa->tx_length = ifa_tx_length(ifa); + ifa->tx_hdrlen = ifa_tx_hdrlen(ifa); ifa->check_link = ip->check_link; ifa->ecmp_weight = ip->ecmp_weight; ifa->check_ttl = (ip->ttl_security == 1); @@ -680,6 +690,7 @@ ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip) ifa->deadint = ip->deadint; ifa->inftransdelay = ip->inftransdelay; ifa->tx_length = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU; + ifa->tx_hdrlen = ifa_tx_hdrlen(ifa); ifa->autype = ip->autype; ifa->passwords = ip->passwords; ifa->instance_id = ip->instance_id; @@ -820,6 +831,9 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new) /* Update passwords */ ifa->passwords = new->passwords; + /* Update header length */ + ifa->tx_hdrlen = ifa_tx_hdrlen(ifa); + /* Remaining options are just for proper interfaces */ if (ifa->type == OSPF_IT_VLINK) return 1; diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index b4d2faba..b88a114d 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -461,7 +461,7 @@ lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *bod } static int -lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body) +lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body UNUSED) { if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt))) return 0; diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 65ad8e3d..157d9628 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -105,7 +105,7 @@ invalid: static inline void -ospf_lsa_lsrq_down(struct top_hash_entry *req, struct ospf_neighbor *n, struct ospf_neighbor *from) +ospf_lsa_lsrq_down(struct top_hash_entry *req, struct ospf_neighbor *n) { if (req == n->lsrqi) n->lsrqi = SNODE_NEXT(req); @@ -188,7 +188,7 @@ ospf_enqueue_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_if { /* If we already have full queue, we send some packets */ uint sent = ospf_flood_lsupd(p, ifa->flood_queue, ifa->flood_queue_used, ifa->flood_queue_used / 2, ifa); - int i; + uint i; for (i = 0; i < sent; i++) ifa->flood_queue[i]->ret_count--; @@ -275,7 +275,7 @@ ospf_flood_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_neig /* If same or newer, remove LSA from the link state request list */ if (cmp > CMP_OLDER) - ospf_lsa_lsrq_down(req, n, from); + ospf_lsa_lsrq_down(req, n); /* If older or same, skip processing of this neighbor */ if (cmp < CMP_NEWER) @@ -330,7 +330,7 @@ ospf_prepare_lsupd(struct ospf_proto *p, struct ospf_iface *ifa, pkt = ospf_tx_buffer(ifa); hlen = ospf_lsupd_hdrlen(p); - maxsize = ospf_pkt_maxsize(p, ifa); + maxsize = ospf_pkt_maxsize(ifa); ospf_pkt_fill_hdr(ifa, pkt, LSUPD_P); pos = hlen; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index 4f445f07..e3eae2b5 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -171,11 +171,7 @@ struct ospf_iface_patt #define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ u8 instance_id; - u8 autype; /* Not really used in OSPFv3 */ -#define OSPF_AUTH_NONE 0 -#define OSPF_AUTH_SIMPLE 1 -#define OSPF_AUTH_CRYPT 2 -#define OSPF_AUTH_CRYPT_SIZE 16 + u8 autype; /* OSPF_AUTH_*, not really used in OSPFv3 */ u8 strictnbma; u8 check_link; u8 ecmp_weight; @@ -325,6 +321,7 @@ struct ospf_iface u8 marked; /* Used in OSPF reconfigure, 2 for force restart */ u16 rxbuf; /* Buffer size */ u16 tx_length; /* Soft TX packet length limit, usually MTU */ + u16 tx_hdrlen; /* Expected packet header length, less than tx_length */ u8 check_link; /* Whether iface link change is used */ u8 ecmp_weight; /* Weight used for ECMP */ u8 link_lsa_suppression; /* Suppression of Link-LSA origination */ @@ -415,6 +412,11 @@ struct ospf_neighbor #define ISM_UNLOOP 5 /* Link up */ #define ISM_DOWN 6 /* Interface down */ +/* OSPF authentication types */ +#define OSPF_AUTH_NONE 0 +#define OSPF_AUTH_SIMPLE 1 +#define OSPF_AUTH_CRYPT 2 + /* OSPF neighbor states */ #define NEIGHBOR_DOWN 0 @@ -446,7 +448,6 @@ struct ospf_neighbor #define TRANS_WAIT 2 /* Waiting before the end of translation */ - /* Generic option flags */ #define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */ #define OPT_E 0x02 /* Related to AS-external LSAs */ @@ -482,7 +483,7 @@ struct ospf_packet u8 autype; /* Undefined for OSPFv3 */ }; -struct ospf_md5 +struct ospf_auth_crypto { u16 zero; u8 keyid; @@ -493,7 +494,7 @@ struct ospf_md5 union ospf_auth { u8 password[8]; - struct ospf_md5 md5; + struct ospf_auth_crypto c32; }; /* Packet types */ @@ -890,8 +891,7 @@ void ospf_sh_neigh_info(struct ospf_neighbor *n); /* packet.c */ void ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type); -uint ospf_pkt_maxsize(struct ospf_proto *p, struct ospf_iface *ifa); -int ospf_rx_hook(sock * sk, int size); +int ospf_rx_hook(sock * sk, uint size); // void ospf_tx_hook(sock * sk); void ospf_err_hook(sock * sk, int err); void ospf_verr_hook(sock *sk, int err); @@ -899,6 +899,9 @@ void ospf_send_to(struct ospf_iface *ifa, ip_addr ip); void ospf_send_to_agt(struct ospf_iface *ifa, u8 state); void ospf_send_to_bdr(struct ospf_iface *ifa); +static inline uint ospf_pkt_maxsize(struct ospf_iface *ifa) +{ return ifa->tx_length - ifa->tx_hdrlen; } + static inline void ospf_send_to_all(struct ospf_iface *ifa) { ospf_send_to(ifa, ifa->all_routers); } diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 7ce6d99f..b84780d3 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -11,6 +11,7 @@ #include "ospf.h" #include "nest/password.h" #include "lib/md5.h" +#include "lib/mac.h" #include "lib/socket.h" void @@ -23,7 +24,7 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) pkt->version = ospf_get_version(p); pkt->type = h_type; - pkt->length = htons(ospf_pkt_maxsize(p, ifa)); + pkt->length = htons(ospf_pkt_maxsize(ifa)); pkt->routerid = htonl(p->router_id); pkt->areaid = htonl(ifa->oa->areaid); pkt->checksum = 0; @@ -31,25 +32,12 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type) pkt->autype = ifa->autype; } -uint -ospf_pkt_maxsize(struct ospf_proto *p, struct ospf_iface *ifa) -{ - uint headers = ospf_is_v2(p) ? IP4_HEADER_LENGTH : IP6_HEADER_LENGTH; - - /* Relevant just for OSPFv2 */ - if (ifa->autype == OSPF_AUTH_CRYPT) - headers += OSPF_AUTH_CRYPT_SIZE; - - return ifa->tx_length - headers; -} - /* We assume OSPFv2 in ospf_pkt_finalize() */ static void -ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) +ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen) { - struct password_item *passwd = NULL; + struct password_item *pass = NULL; union ospf_auth *auth = (void *) (pkt + 1); - uint plen = ntohs(pkt->length); pkt->checksum = 0; pkt->autype = ifa->autype; @@ -61,25 +49,25 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) switch (ifa->autype) { case OSPF_AUTH_SIMPLE: - passwd = password_find(ifa->passwords, 1); - if (!passwd) + pass = password_find(ifa->passwords, 1); + if (!pass) { log(L_ERR "No suitable password found for authentication"); return; } - strncpy(auth->password, passwd->password, sizeof(auth->password)); + strncpy(auth->password, pass->password, sizeof(auth->password)); case OSPF_AUTH_NONE: { void *body = (void *) (auth + 1); - uint blen = plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth); + uint blen = *plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth); pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL); } break; case OSPF_AUTH_CRYPT: - passwd = password_find(ifa->passwords, 0); - if (!passwd) + pass = password_find(ifa->passwords, 0); + if (!pass) { log(L_ERR "No suitable password found for authentication"); return; @@ -100,20 +88,25 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) ifa->csn_use = now; - auth->md5.zero = 0; - auth->md5.keyid = passwd->id; - auth->md5.len = OSPF_AUTH_CRYPT_SIZE; - auth->md5.csn = htonl(ifa->csn); + uint auth_len = mac_type_length(pass->alg); + byte *auth_tail = ((byte *) pkt + *plen); + *plen += auth_len; + + ASSERT(*plen < ifa->sk->tbsize); - void *tail = ((void *) pkt) + plen; - char password[OSPF_AUTH_CRYPT_SIZE]; - strncpy(password, passwd->password, sizeof(password)); + auth->c32.zero = 0; + auth->c32.keyid = pass->id; + auth->c32.len = auth_len; + auth->c32.csn = htonl(ifa->csn); - struct md5_context ctx; - md5_init(&ctx); - md5_update(&ctx, (char *) pkt, plen); - md5_update(&ctx, password, OSPF_AUTH_CRYPT_SIZE); - memcpy((byte *) tail, md5_final(&ctx), MD5_SIZE); + /* Append key for keyed hash, append padding for HMAC (RFC 5709 3.3) */ + if (pass->alg < ALG_HMAC) + strncpy(auth_tail, pass->password, auth_len); + else + memset32(auth_tail, HMAC_MAGIC, auth_len / 4); + + mac_fill(pass->alg, pass->password, pass->length, + (byte *) pkt, *plen, auth_tail); break; default: @@ -124,7 +117,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt) /* We assume OSPFv2 in ospf_pkt_checkauth() */ static int -ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int len) +ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, uint len) { struct ospf_proto *p = ifa->oa->po; union ospf_auth *auth = (void *) (pkt + 1); @@ -154,13 +147,19 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ return 1; case OSPF_AUTH_CRYPT: - if (auth->md5.len != OSPF_AUTH_CRYPT_SIZE) - DROP("invalid MD5 digest length", auth->md5.len); + pass = password_find_by_id(ifa->passwords, auth->c32.keyid); + if (!pass) + DROP("no suitable password found", auth->c32.keyid); + + uint auth_len = mac_type_length(pass->alg); - if (plen + OSPF_AUTH_CRYPT_SIZE > len) - DROP("length mismatch", len); + if (plen + auth->c32.len > len) + DROP("packet length mismatch", len); - u32 rcv_csn = ntohl(auth->md5.csn); + if (auth->c32.len != auth_len) + DROP("wrong authentication length", auth->c32.len); + + u32 rcv_csn = ntohl(auth->c32.csn); if (n && (rcv_csn < n->csn)) // DROP("lower sequence number", rcv_csn); { @@ -171,22 +170,19 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_ return 0; } - pass = password_find_by_id(ifa->passwords, auth->md5.keyid); - if (!pass) - DROP("no suitable password found", auth->md5.keyid); - - byte *tail = ((byte *) pkt) + plen; - char received[OSPF_AUTH_CRYPT_SIZE]; - memcpy(received, tail, OSPF_AUTH_CRYPT_SIZE); - strncpy(tail, pass->password, OSPF_AUTH_CRYPT_SIZE); + byte *auth_tail = ((byte *) pkt) + plen; + byte *auth_data = alloca(auth_len); + memcpy(auth_data, auth_tail, auth_len); - struct md5_context ctx; - md5_init(&ctx); - md5_update(&ctx, (byte *) pkt, plen + OSPF_AUTH_CRYPT_SIZE); - char *computed = md5_final(&ctx); + /* Append key for keyed hash, append padding for HMAC (RFC 5709 3.3) */ + if (pass->alg < ALG_HMAC) + strncpy(auth_tail, pass->password, auth_len); + else + memset32(auth_tail, HMAC_MAGIC, auth_len / 4); - if (memcmp(received, computed, OSPF_AUTH_CRYPT_SIZE)) - DROP("wrong MD5 digest", pass->id); + if (!mac_verify(pass->alg, pass->password, pass->length, + (byte *) pkt, plen + auth_len, auth_data)) + DROP("wrong authentication code", pass->id); if (n) n->csn = rcv_csn; @@ -214,7 +210,7 @@ drop: * non generic functions. */ int -ospf_rx_hook(sock *sk, int len) +ospf_rx_hook(sock *sk, uint len) { /* We want just packets from sk->iface. Unfortunately, on BSD we cannot filter out other packets at kernel level and we receive all packets on all sockets */ @@ -472,15 +468,10 @@ ospf_send_to(struct ospf_iface *ifa, ip_addr dst) { sock *sk = ifa->sk; struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; - int plen = ntohs(pkt->length); + uint plen = ntohs(pkt->length); if (ospf_is_v2(ifa->oa->po)) - { - if (ifa->autype == OSPF_AUTH_CRYPT) - plen += OSPF_AUTH_CRYPT_SIZE; - - ospf_pkt_finalize(ifa, pkt); - } + ospf_pkt_finalize(ifa, pkt, &plen); int done = sk_send_to(sk, plen, dst, 0); if (!done) diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 5538f4c8..c5c54783 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -671,7 +671,7 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry which may be later used as the next hop. */ /* In OSPFv2, en->lb is set here. In OSPFv3, en->lb is just cleared here, - it is set in process_prefixes() to any global addres in the area */ + it is set in process_prefixes() to any global address in the area */ en->lb = IPA_NONE; en->lb_id = 0; @@ -923,7 +923,7 @@ ospf_rt_sum_tr(struct ospf_area *oa) } } -/* Decide about originating or flushing summary LSAs for condended area networks */ +/* Decide about originating or flushing summary LSAs for condensed area networks */ static int decide_anet_lsa(struct ospf_area *oa, struct area_net *anet, struct ospf_area *anet_oa) { diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 86e39d75..aaaf2e8e 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -513,6 +513,7 @@ ospf_update_lsadb(struct ospf_proto *p) } } + static u32 ort_to_lsaid(struct ospf_proto *p, ort *nf) { @@ -610,7 +611,7 @@ lsab_offset(struct ospf_proto *p, uint offset) return ((byte *) p->lsab) + offset; } -static inline void * +static inline void * UNUSED lsab_end(struct ospf_proto *p) { return ((byte *) p->lsab) + p->lsab_used; @@ -1558,7 +1559,7 @@ static void add_link_lsa(struct ospf_proto *p, struct ospf_lsa_link *ll, int offset, int *pxc) { u32 *pxb = ll->rest; - int j; + uint j; for (j = 0; j < ll->pxcount; pxb = prefix_advance(pxb), j++) { diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c index d40b3f91..8924c200 100644 --- a/proto/pipe/pipe.c +++ b/proto/pipe/pipe.c @@ -191,7 +191,7 @@ pipe_reconfigure(struct proto *P, struct proto_config *CF) } static void -pipe_copy_config(struct proto_config *dest, struct proto_config *src) +pipe_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED) { /* Just a shallow copy, not many items here */ } diff --git a/proto/radv/packets.c b/proto/radv/packets.c index 915b412f..f4352155 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -156,12 +156,12 @@ radv_process_domain(struct radv_dnssl_config *cf) char *dom = cf->domain; char *dom_end = dom; /* Just to */ u8 *dlen_save = &cf->dlen_first; - int len; + uint len; while (dom_end) { dom_end = strchr(dom, '.'); - len = dom_end ? (dom_end - dom) : strlen(dom); + len = dom_end ? (uint)(dom_end - dom) : strlen(dom); if (len < 1 || len > 63) return -1; @@ -349,7 +349,7 @@ radv_send_ra(struct radv_iface *ifa, int shutdown) static int -radv_rx_hook(sock *sk, int size) +radv_rx_hook(sock *sk, uint size) { struct radv_iface *ifa = sk->data; struct proto_radv *ra = ifa->ra; diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 4c845f7a..44b44879 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -240,7 +240,7 @@ radv_if_notify(struct proto *p, unsigned flags, struct iface *iface) } static void -radv_ifa_notify(struct proto *p, unsigned flags, struct ifa *a) +radv_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a) { struct proto_radv *ra = (struct proto_radv *) p; diff --git a/proto/rip/config.Y b/proto/rip/config.Y index 61a2a101..b3ccdf39 100644 --- a/proto/rip/config.Y +++ b/proto/rip/config.Y @@ -104,15 +104,29 @@ rip_iface_start: rip_iface_finish: { + /* Default mode is broadcast for RIPv1, multicast for RIPv2 and RIPng */ + if (!RIP_IFACE->mode) + RIP_IFACE->mode = (rip_cfg_is_v2() && (RIP_IFACE->version == RIP_V1)) ? + RIP_IM_BROADCAST : RIP_IM_MULTICAST; + RIP_IFACE->passwords = get_passwords(); if (!RIP_IFACE->auth_type != !RIP_IFACE->passwords) log(L_WARN "Authentication and password options should be used together"); - /* Default mode is broadcast for RIPv1, multicast for RIPv2 and RIPng */ - if (!RIP_IFACE->mode) - RIP_IFACE->mode = (rip_cfg_is_v2() && (RIP_IFACE->version == RIP_V1)) ? - RIP_IM_BROADCAST : RIP_IM_MULTICAST; + if (RIP_IFACE->passwords) + { + struct password_item *pass; + WALK_LIST(pass, *RIP_IFACE->passwords) + { + if (pass->alg && (RIP_IFACE->auth_type != RIP_AUTH_CRYPTO)) + cf_error("Password algorithm option requires cryptographic authentication"); + + /* Set default crypto algorithm (MD5) */ + if (!pass->alg && (RIP_IFACE->auth_type == RIP_AUTH_CRYPTO)) + pass->alg = ALG_MD5; + } + } RIP_CFG->min_timeout_time = MIN_(RIP_CFG->min_timeout_time, RIP_IFACE->timeout_time); RIP_CFG->max_garbage_time = MAX_(RIP_CFG->max_garbage_time, RIP_IFACE->garbage_time); @@ -153,7 +167,7 @@ rip_auth: NONE { $$ = RIP_AUTH_NONE; } | PLAINTEXT { $$ = RIP_AUTH_PLAIN; } | CRYPTOGRAPHIC { $$ = RIP_AUTH_CRYPTO; } - | MD5 { $$ = RIP_AUTH_CRYPTO; } + | MD5 { $$ = RIP_AUTH_CRYPTO; } /* For backward compatibility */ ; rip_iface_opts: diff --git a/proto/rip/packets.c b/proto/rip/packets.c index f89bb178..9dc492b7 100644 --- a/proto/rip/packets.c +++ b/proto/rip/packets.c @@ -12,16 +12,14 @@ #undef LOCAL_DEBUG #include "rip.h" -#include "lib/md5.h" +#include "lib/mac.h" #define RIP_CMD_REQUEST 1 /* want info */ #define RIP_CMD_RESPONSE 2 /* responding to request */ #define RIP_BLOCK_LENGTH 20 - #define RIP_PASSWD_LENGTH 16 -#define RIP_MD5_LENGTH 16 #define RIP_AF_IPV4 2 #define RIP_AF_AUTH 0xffff @@ -74,7 +72,7 @@ struct rip_auth_tail { u16 must_be_ffff; u16 must_be_0001; - byte auth_data[]; + byte auth_data[0]; }; /* Internal representation of RTE block data */ @@ -132,7 +130,7 @@ rip_put_block(struct rip_proto *p, byte *pos, struct rip_block *rte) } static inline void -rip_put_next_hop(struct rip_proto *p, byte *pos, struct rip_block *rte) +rip_put_next_hop(struct rip_proto *p UNUSED, byte *pos, struct rip_block *rte) { struct rip_block_ng *block = (void *) pos; block->prefix = ip6_hton(ipa_to_ip6(rte->next_hop)); @@ -221,16 +219,24 @@ rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_p auth->auth_type = htons(RIP_AUTH_CRYPTO); auth->packet_len = htons(*plen); auth->key_id = pass->id; - auth->auth_len = sizeof(struct rip_auth_tail) + RIP_MD5_LENGTH; + auth->auth_len = mac_type_length(pass->alg); auth->seq_num = ifa->csn_ready ? htonl(ifa->csn) : 0; auth->unused1 = 0; auth->unused2 = 0; ifa->csn_ready = 1; + if (pass->alg < ALG_HMAC) + auth->auth_len += sizeof(struct rip_auth_tail); + /* * Note that RFC 4822 is unclear whether auth_len should cover whole * authentication trailer or just auth_data length. * + * FIXME: We should use just auth_data length by default. Currently we put + * the whole auth trailer length in keyed hash case to keep old behavior, + * but we put just auth_data length in the new HMAC case. Note that Quagga + * has config option for this. + * * Crypto sequence numbers are increased by sender in rip_update_csn(). * First CSN should be zero, this is handled by csn_ready. */ @@ -238,14 +244,18 @@ rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_p struct rip_auth_tail *tail = (void *) ((byte *) pkt + *plen); tail->must_be_ffff = htons(0xffff); tail->must_be_0001 = htons(0x0001); - strncpy(tail->auth_data, pass->password, RIP_MD5_LENGTH); - *plen += sizeof(struct rip_auth_tail) + RIP_MD5_LENGTH; + uint auth_len = mac_type_length(pass->alg); + *plen += sizeof(struct rip_auth_tail) + auth_len; - struct md5_context ctx; - md5_init(&ctx); - md5_update(&ctx, (byte *) pkt, *plen); - memcpy(tail->auth_data, md5_final(&ctx), RIP_MD5_LENGTH); + /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */ + if (pass->alg < ALG_HMAC) + strncpy(tail->auth_data, pass->password, auth_len); + else + memset32(tail->auth_data, HMAC_MAGIC, auth_len / 4); + + mac_fill(pass->alg, pass->password, pass->length, + (byte *) pkt, *plen, tail->auth_data); return; default: @@ -288,13 +298,25 @@ rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_ DROP("no suitable password found", auth->key_id); uint data_len = ntohs(auth->packet_len); - uint auth_len = sizeof(struct rip_auth_tail) + RIP_MD5_LENGTH; + uint auth_len = mac_type_length(pass->alg); + uint auth_len2 = sizeof(struct rip_auth_tail) + auth_len; - if (data_len + auth_len != *plen) - DROP("packet length mismatch", data_len); + /* + * Ideally, first check should be check for internal consistency: + * (data_len + sizeof(struct rip_auth_tail) + auth->auth_len) != *plen + * + * Second one should check expected code length: + * auth->auth_len != auth_len + * + * But as auth->auth_len has two interpretations, we simplify this + */ - if ((auth->auth_len != RIP_MD5_LENGTH) && (auth->auth_len != auth_len)) - DROP("authentication data length mismatch", auth->auth_len); + if (data_len + auth_len2 != *plen) + DROP("packet length mismatch", *plen); + + /* Warning: two interpretations of auth_len field */ + if ((auth->auth_len != auth_len) && (auth->auth_len != auth_len2)) + DROP("wrong authentication length", auth->auth_len); struct rip_auth_tail *tail = (void *) ((byte *) pkt + data_len); if ((tail->must_be_ffff != htons(0xffff)) || (tail->must_be_0001 != htons(0x0001))) @@ -312,17 +334,18 @@ rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_ return 0; } - char received[RIP_MD5_LENGTH]; - memcpy(received, tail->auth_data, RIP_MD5_LENGTH); - strncpy(tail->auth_data, pass->password, RIP_MD5_LENGTH); + byte *auth_data = alloca(auth_len); + memcpy(auth_data, tail->auth_data, auth_len); - struct md5_context ctx; - md5_init(&ctx); - md5_update(&ctx, (byte *) pkt, *plen); - char *computed = md5_final(&ctx); + /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */ + if (pass->alg < ALG_HMAC) + strncpy(tail->auth_data, pass->password, auth_len); + else + memset32(tail->auth_data, HMAC_MAGIC, auth_len / 4); - if (memcmp(received, computed, RIP_MD5_LENGTH)) - DROP("wrong MD5 digest", pass->id); + if (!mac_verify(pass->alg, pass->password, pass->length, + (byte *) pkt, *plen, auth_data)) + DROP("wrong authentication code", pass->id); *plen = data_len; n->csn = rcv_csn; @@ -632,7 +655,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack } static int -rip_rx_hook(sock *sk, int len) +rip_rx_hook(sock *sk, uint len) { struct rip_iface *ifa = sk->data; struct rip_proto *p = ifa->rip; diff --git a/proto/rip/rip.c b/proto/rip/rip.c index 74d472c9..d87a078c 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -575,7 +575,7 @@ rip_iface_update_buffers(struct rip_iface *ifa) ifa->tx_plen = tbsize - headers; if (ifa->cf->auth_type == RIP_AUTH_CRYPTO) - ifa->tx_plen -= RIP_AUTH_TAIL_LENGTH; + ifa->tx_plen -= RIP_AUTH_TAIL_LENGTH + max_mac_length(ifa->cf->passwords); } static inline void @@ -687,12 +687,11 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa ifa->cf = new; + rip_iface_update_buffers(ifa); + if (ifa->next_regular > (now + new->update_time)) ifa->next_regular = now + (random() % new->update_time) + 1; - if ((new->tx_length != old->tx_length) || (new->rx_buffer != old->rx_buffer)) - rip_iface_update_buffers(ifa); - if (new->check_link != old->check_link) rip_iface_update_state(ifa); @@ -1011,7 +1010,7 @@ rip_prepare_attrs(struct linpool *pool, ea_list *next, u8 metric, u16 tag) } static int -rip_import_control(struct proto *P, struct rte **rt, struct ea_list **attrs, struct linpool *pool) +rip_import_control(struct proto *P UNUSED, struct rte **rt, struct ea_list **attrs, struct linpool *pool) { /* Prepare attributes with initial values */ if ((*rt)->attrs->source != RTS_RIP) @@ -1145,7 +1144,7 @@ rip_reconfigure(struct proto *P, struct proto_config *CF) } static void -rip_get_route_info(rte *rte, byte *buf, ea_list *attrs) +rip_get_route_info(rte *rte, byte *buf, ea_list *attrs UNUSED) { buf += bsprintf(buf, " (%d/%d)", rte->pref, rte->u.rip.metric); diff --git a/proto/rip/rip.h b/proto/rip/rip.h index 7ec7e24d..03dc9138 100644 --- a/proto/rip/rip.h +++ b/proto/rip/rip.h @@ -34,7 +34,7 @@ #define RIP_NG_PORT 521 /* RIPng */ #define RIP_MAX_PKT_LENGTH 532 /* 512 + IP4_HEADER_LENGTH */ -#define RIP_AUTH_TAIL_LENGTH 20 /* 4 + MD5 length */ +#define RIP_AUTH_TAIL_LENGTH 4 /* Without auth_data */ #define RIP_DEFAULT_ECMP_LIMIT 16 #define RIP_DEFAULT_INFINITY 16 diff --git a/proto/static/static.c b/proto/static/static.c index a8abdef0..b5e717ca 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -244,7 +244,7 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r) } static void -static_rte_cleanup(struct proto *p, struct static_route *r) +static_rte_cleanup(struct proto *p UNUSED, struct static_route *r) { struct static_route *r2; @@ -440,7 +440,7 @@ static_if_notify(struct proto *p, unsigned flags, struct iface *i) } int -static_rte_mergable(rte *pri, rte *sec) +static_rte_mergable(rte *pri UNUSED, rte *sec UNUSED) { return 1; } |