OSPF: Support of authentication trailer for OSPFv3
Implement RFC 7166, crypthographic authentication for OSPFv3 analogous to authentication used for OSPFv2.
This commit is contained in:
parent
f3a8cf050e
commit
4727d1db9d
7 changed files with 265 additions and 46 deletions
|
@ -37,7 +37,7 @@ ospf_iface_finish(void)
|
||||||
|
|
||||||
ip->passwords = get_passwords();
|
ip->passwords = get_passwords();
|
||||||
|
|
||||||
if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
|
if (ospf_cfg_is_v2() && (ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
|
||||||
log(L_WARN "Hello or poll interval less that 5 makes cryptographic authenication prone to replay attacks");
|
log(L_WARN "Hello or poll interval less that 5 makes cryptographic authenication prone to replay attacks");
|
||||||
|
|
||||||
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
|
if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
|
||||||
|
@ -54,6 +54,9 @@ ospf_iface_finish(void)
|
||||||
/* Set default OSPF crypto algorithms */
|
/* Set default OSPF crypto algorithms */
|
||||||
if (!pass->alg && (ip->autype == OSPF_AUTH_CRYPT))
|
if (!pass->alg && (ip->autype == OSPF_AUTH_CRYPT))
|
||||||
pass->alg = ospf_cfg_is_v2() ? ALG_MD5 : ALG_HMAC_SHA256;
|
pass->alg = ospf_cfg_is_v2() ? ALG_MD5 : ALG_HMAC_SHA256;
|
||||||
|
|
||||||
|
if (ospf_cfg_is_v3() && ip->autype && (pass->alg < ALG_HMAC))
|
||||||
|
cf_error("Keyed hash algorithms are not allowed, use HMAC algorithms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +184,7 @@ static inline void
|
||||||
ospf_check_auth(void)
|
ospf_check_auth(void)
|
||||||
{
|
{
|
||||||
if (ospf_cfg_is_v3())
|
if (ospf_cfg_is_v3())
|
||||||
cf_error("Authentication not supported in OSPFv3");
|
cf_error("Plaintext authentication not supported in OSPFv3");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -346,8 +349,8 @@ ospf_vlink_item:
|
||||||
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
| DEAD COUNT expr { OSPF_PATT->deadc = $3 ; if ($3<=1) cf_error("Dead count must be greater than one"); }
|
||||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
|
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
|
||||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
|
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
|
||||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
|
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; }
|
||||||
| password_list { ospf_check_auth(); }
|
| password_list
|
||||||
;
|
;
|
||||||
|
|
||||||
ospf_vlink_start: VIRTUAL LINK idval
|
ospf_vlink_start: VIRTUAL LINK idval
|
||||||
|
@ -396,7 +399,7 @@ ospf_iface_item:
|
||||||
| NEIGHBORS '{' nbma_list '}'
|
| NEIGHBORS '{' nbma_list '}'
|
||||||
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
|
| AUTHENTICATION NONE { OSPF_PATT->autype = OSPF_AUTH_NONE; }
|
||||||
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
|
| AUTHENTICATION SIMPLE { OSPF_PATT->autype = OSPF_AUTH_SIMPLE; ospf_check_auth(); }
|
||||||
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; ospf_check_auth(); }
|
| AUTHENTICATION CRYPTOGRAPHIC { OSPF_PATT->autype = OSPF_AUTH_CRYPT; }
|
||||||
| RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
|
| RX BUFFER NORMAL { OSPF_PATT->rx_buffer = 0; }
|
||||||
| RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
|
| RX BUFFER LARGE { OSPF_PATT->rx_buffer = OSPF_MAX_PKT_SIZE; }
|
||||||
| RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
|
| RX BUFFER expr { OSPF_PATT->rx_buffer = $3; if (($3 < OSPF_MIN_PKT_SIZE) || ($3 > OSPF_MAX_PKT_SIZE)) cf_error("Buffer size must be in range 256-65535"); }
|
||||||
|
@ -406,7 +409,7 @@ ospf_iface_item:
|
||||||
| TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
|
| TTL SECURITY bool { OSPF_PATT->ttl_security = $3; }
|
||||||
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
|
| TTL SECURITY TX ONLY { OSPF_PATT->ttl_security = 2; }
|
||||||
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
|
| BFD bool { OSPF_PATT->bfd = $2; cf_check_bfd($2); }
|
||||||
| password_list { ospf_check_auth(); }
|
| password_list
|
||||||
;
|
;
|
||||||
|
|
||||||
pref_list:
|
pref_list:
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
struct ospf_dbdes2_packet
|
struct ospf_dbdes2_packet
|
||||||
{
|
{
|
||||||
struct ospf_packet hdr;
|
struct ospf_packet hdr;
|
||||||
union ospf_auth auth;
|
union ospf_auth2 auth;
|
||||||
|
|
||||||
u16 iface_mtu;
|
u16 iface_mtu;
|
||||||
u8 options;
|
u8 options;
|
||||||
|
@ -38,6 +38,13 @@ struct ospf_dbdes3_packet
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
uint
|
||||||
|
ospf_dbdes3_options(struct ospf_packet *pkt)
|
||||||
|
{
|
||||||
|
struct ospf_dbdes3_packet *ps = (void *) pkt;
|
||||||
|
return ntohl(ps->options);
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint
|
static inline uint
|
||||||
ospf_dbdes_hdrlen(struct ospf_proto *p)
|
ospf_dbdes_hdrlen(struct ospf_proto *p)
|
||||||
{
|
{
|
||||||
|
@ -45,7 +52,6 @@ ospf_dbdes_hdrlen(struct ospf_proto *p)
|
||||||
sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
|
sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
|
ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
|
||||||
struct ospf_lsa_header **body, uint *count)
|
struct ospf_lsa_header **body, uint *count)
|
||||||
|
@ -129,7 +135,7 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
|
||||||
else /* OSPFv3 */
|
else /* OSPFv3 */
|
||||||
{
|
{
|
||||||
struct ospf_dbdes3_packet *ps = (void *) pkt;
|
struct ospf_dbdes3_packet *ps = (void *) pkt;
|
||||||
ps->options = htonl(ifa->oa->options);
|
ps->options = htonl(ifa->oa->options | (ifa->autype == OSPF_AUTH_CRYPT ? OPT_AT : 0));
|
||||||
ps->iface_mtu = htons(iface_mtu);
|
ps->iface_mtu = htons(iface_mtu);
|
||||||
ps->padding = 0;
|
ps->padding = 0;
|
||||||
ps->imms = 0; /* Will be set later */
|
ps->imms = 0; /* Will be set later */
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
struct ospf_hello2_packet
|
struct ospf_hello2_packet
|
||||||
{
|
{
|
||||||
struct ospf_packet hdr;
|
struct ospf_packet hdr;
|
||||||
union ospf_auth auth;
|
union ospf_auth2 auth;
|
||||||
|
|
||||||
u32 netmask;
|
u32 netmask;
|
||||||
u16 helloint;
|
u16 helloint;
|
||||||
|
@ -42,6 +42,13 @@ struct ospf_hello3_packet
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
uint
|
||||||
|
ospf_hello3_options(struct ospf_packet *pkt)
|
||||||
|
{
|
||||||
|
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||||
|
return ntohl(ps->options) & 0x00FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||||
{
|
{
|
||||||
|
@ -86,9 +93,10 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct ospf_hello3_packet *ps = (void *) pkt;
|
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||||
|
u32 options = ifa->oa->options | (ifa->autype == OSPF_AUTH_CRYPT ? OPT_AT : 0);
|
||||||
|
|
||||||
ps->iface_id = htonl(ifa->iface_id);
|
ps->iface_id = htonl(ifa->iface_id);
|
||||||
ps->options = ntohl(ifa->oa->options | (ifa->priority << 24));
|
ps->options = ntohl(options | (ifa->priority << 24));
|
||||||
ps->helloint = ntohs(ifa->helloint);
|
ps->helloint = ntohs(ifa->helloint);
|
||||||
ps->deadint = htons(ifa->deadint);
|
ps->deadint = htons(ifa->deadint);
|
||||||
ps->dr = htonl(ifa->drid);
|
ps->dr = htonl(ifa->drid);
|
||||||
|
@ -334,7 +342,6 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||||
n->priority = rcv_priority;
|
n->priority = rcv_priority;
|
||||||
n->iface_id = rcv_iface_id;
|
n->iface_id = rcv_iface_id;
|
||||||
|
|
||||||
|
|
||||||
/* Update inactivity timer */
|
/* Update inactivity timer */
|
||||||
ospf_neigh_sm(n, INM_HELLOREC);
|
ospf_neigh_sm(n, INM_HELLOREC);
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,10 @@ ifa_tx_hdrlen(struct ospf_iface *ifa)
|
||||||
|
|
||||||
/* Relevant just for OSPFv2 */
|
/* Relevant just for OSPFv2 */
|
||||||
if (ifa->autype == OSPF_AUTH_CRYPT)
|
if (ifa->autype == OSPF_AUTH_CRYPT)
|
||||||
|
{
|
||||||
|
hlen += ospf_is_v2(p) ? 0 : sizeof(struct ospf_auth3);
|
||||||
hlen += max_mac_length(ifa->passwords);
|
hlen += max_mac_length(ifa->passwords);
|
||||||
|
}
|
||||||
|
|
||||||
return hlen;
|
return hlen;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +140,7 @@ ospf_sk_open(struct ospf_iface *ifa)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/* 12 is an offset of the checksum in an OSPFv3 packet */
|
/* 12 is an offset of the checksum in an OSPFv3 packet */
|
||||||
if (ospf_is_v3(p))
|
if (ospf_is_v3(p) && !ifa->autype)
|
||||||
if (sk_set_ipv6_checksum(sk, 12) < 0)
|
if (sk_set_ipv6_checksum(sk, 12) < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -828,6 +831,14 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
|
||||||
{
|
{
|
||||||
OSPF_TRACE(D_EVENTS, "Changing authentication type of %s", ifname);
|
OSPF_TRACE(D_EVENTS, "Changing authentication type of %s", ifname);
|
||||||
ifa->autype = new->autype;
|
ifa->autype = new->autype;
|
||||||
|
|
||||||
|
/* For OSPFv3, we need to update checksum calculation by OS */
|
||||||
|
if (ospf_is_v3(p) && ifa->sk)
|
||||||
|
if (sk_set_ipv6_checksum(ifa->sk, ifa->autype ? -1 : 12) < 0)
|
||||||
|
{
|
||||||
|
sk_log_error(ifa->sk, p->p.name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update passwords */
|
/* Update passwords */
|
||||||
|
|
|
@ -84,8 +84,6 @@ ospf_neighbor_new(struct ospf_iface *ifa)
|
||||||
n->pool = pool;
|
n->pool = pool;
|
||||||
n->ifa = ifa;
|
n->ifa = ifa;
|
||||||
add_tail(&ifa->neigh_list, NODE n);
|
add_tail(&ifa->neigh_list, NODE n);
|
||||||
n->adj = 0;
|
|
||||||
n->csn = 0;
|
|
||||||
n->state = NEIGHBOR_DOWN;
|
n->state = NEIGHBOR_DOWN;
|
||||||
|
|
||||||
init_lists(p, n);
|
init_lists(p, n);
|
||||||
|
|
|
@ -69,6 +69,9 @@
|
||||||
#define MINLSARRIVAL (1 S_)
|
#define MINLSARRIVAL (1 S_)
|
||||||
#define LSINFINITY 0xffffff
|
#define LSINFINITY 0xffffff
|
||||||
|
|
||||||
|
#define OSPF_PKT_TYPES 5 /* HELLO_P .. LSACK_P */
|
||||||
|
#define OSPF3_CRYPTO_ID 1 /* OSPFv3 Cryptographic Protocol ID */
|
||||||
|
|
||||||
#define OSPF_DEFAULT_TICK 1
|
#define OSPF_DEFAULT_TICK 1
|
||||||
#define OSPF_DEFAULT_STUB_COST 1000
|
#define OSPF_DEFAULT_STUB_COST 1000
|
||||||
#define OSPF_DEFAULT_ECMP_LIMIT 16
|
#define OSPF_DEFAULT_ECMP_LIMIT 16
|
||||||
|
@ -222,6 +225,7 @@ struct ospf_proto
|
||||||
u8 merge_external; /* Should i merge external routes? */
|
u8 merge_external; /* Should i merge external routes? */
|
||||||
u8 asbr; /* May i originate any ext/NSSA lsa? */
|
u8 asbr; /* May i originate any ext/NSSA lsa? */
|
||||||
u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
|
u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
|
||||||
|
u64 csn64; /* Last used cryptographic sequence number */
|
||||||
struct ospf_area *backbone; /* If exists */
|
struct ospf_area *backbone; /* If exists */
|
||||||
event *flood_event; /* Event for flooding LS updates */
|
event *flood_event; /* Event for flooding LS updates */
|
||||||
void *lsab; /* LSA buffer used when originating router LSAs */
|
void *lsab; /* LSA buffer used when originating router LSAs */
|
||||||
|
@ -254,8 +258,6 @@ struct ospf_area
|
||||||
struct fib rtr; /* Routing tables for routers */
|
struct fib rtr; /* Routing tables for routers */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct ospf_iface
|
struct ospf_iface
|
||||||
{
|
{
|
||||||
node n;
|
node n;
|
||||||
|
@ -387,7 +389,8 @@ struct ospf_neighbor
|
||||||
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
||||||
void *ldd_buffer; /* Last database description packet */
|
void *ldd_buffer; /* Last database description packet */
|
||||||
u32 ldd_bsize; /* Buffer size for ldd_buffer */
|
u32 ldd_bsize; /* Buffer size for ldd_buffer */
|
||||||
u32 csn; /* Last received crypt seq number (for MD5) */
|
u32 csn; /* OSPFv2: Last received crypt seq number */
|
||||||
|
u64 csn64[OSPF_PKT_TYPES]; /* OSPFv3: Last received CSN for each type of packet */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -422,6 +425,7 @@ struct ospf_neighbor
|
||||||
#define OSPF_AUTH_SIMPLE 1
|
#define OSPF_AUTH_SIMPLE 1
|
||||||
#define OSPF_AUTH_CRYPT 2
|
#define OSPF_AUTH_CRYPT 2
|
||||||
|
|
||||||
|
#define OSPF3_AUTH_HMAC 1 /* HMAC Cryptographic Authentication */
|
||||||
|
|
||||||
/* OSPF neighbor states */
|
/* OSPF neighbor states */
|
||||||
#define NEIGHBOR_DOWN 0
|
#define NEIGHBOR_DOWN 0
|
||||||
|
@ -459,10 +463,12 @@ struct ospf_neighbor
|
||||||
#define OPT_MC 0x0004 /* Related to MOSPF, not used and obsolete */
|
#define OPT_MC 0x0004 /* Related to MOSPF, not used and obsolete */
|
||||||
#define OPT_N 0x0008 /* Related to NSSA */
|
#define OPT_N 0x0008 /* Related to NSSA */
|
||||||
#define OPT_P 0x0008 /* OSPFv2, flags P and N share position, see NSSA RFC */
|
#define OPT_P 0x0008 /* OSPFv2, flags P and N share position, see NSSA RFC */
|
||||||
#define OPT_EA 0x0010 /* OSPFv2, external attributes, not used and obsolete */
|
#define OPT_L_V2 0x0010 /* OSPFv2, link-local signaling, not used */
|
||||||
#define OPT_R 0x0010 /* OSPFv3, originator is active router */
|
#define OPT_R 0x0010 /* OSPFv3, originator is active router */
|
||||||
#define OPT_DC 0x0020 /* Related to demand circuits, not used */
|
#define OPT_DC 0x0020 /* Related to demand circuits, not used */
|
||||||
#define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */
|
#define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */
|
||||||
|
#define OPT_L_V3 0x0200 /* OSPFv3, link-local signaling */
|
||||||
|
#define OPT_AT 0x0400 /* OSPFv3, authentication trailer */
|
||||||
|
|
||||||
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
|
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
|
||||||
#define OPT_RT_B (0x01 << 24)
|
#define OPT_RT_B (0x01 << 24)
|
||||||
|
@ -489,20 +495,38 @@ struct ospf_packet
|
||||||
u8 autype; /* Undefined for OSPFv3 */
|
u8 autype; /* Undefined for OSPFv3 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ospf_lls
|
||||||
|
{
|
||||||
|
u16 checksum;
|
||||||
|
u16 length;
|
||||||
|
byte data[0];
|
||||||
|
};
|
||||||
|
|
||||||
struct ospf_auth_crypto
|
struct ospf_auth_crypto
|
||||||
{
|
{
|
||||||
u16 zero;
|
u16 zero;
|
||||||
u8 keyid;
|
u8 keyid;
|
||||||
u8 len;
|
u8 len;
|
||||||
u32 csn;
|
u32 csn; /* Cryptographic sequence number (32-bit) */
|
||||||
};
|
};
|
||||||
|
|
||||||
union ospf_auth
|
union ospf_auth2
|
||||||
{
|
{
|
||||||
u8 password[8];
|
u8 password[8];
|
||||||
struct ospf_auth_crypto c32;
|
struct ospf_auth_crypto c32;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ospf_auth3
|
||||||
|
{
|
||||||
|
u16 type; /* Authentication type (OSPF3_AUTH_*) */
|
||||||
|
u16 length; /* Authentication trailer length (header + data) */
|
||||||
|
u16 reserved;
|
||||||
|
u16 sa_id; /* Security association identifier (key_id) */
|
||||||
|
u64 csn; /* Cryptographic sequence number (64-bit) */
|
||||||
|
byte data[0]; /* Authentication data */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Packet types */
|
/* Packet types */
|
||||||
#define HELLO_P 1 /* Hello */
|
#define HELLO_P 1 /* Hello */
|
||||||
#define DBDES_P 2 /* Database description */
|
#define DBDES_P 2 /* Database description */
|
||||||
|
@ -957,7 +981,7 @@ static inline void ospf_send_to_des(struct ospf_iface *ifa)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline uint ospf_pkt_hdrlen(struct ospf_proto *p)
|
static inline uint ospf_pkt_hdrlen(struct ospf_proto *p)
|
||||||
{ return ospf_is_v2(p) ? (sizeof(struct ospf_packet) + sizeof(union ospf_auth)) : sizeof(struct ospf_packet); }
|
{ return ospf_is_v2(p) ? (sizeof(struct ospf_packet) + sizeof(union ospf_auth2)) : sizeof(struct ospf_packet); }
|
||||||
|
|
||||||
static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
|
static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
|
||||||
{ return ifa->sk->tbuf; }
|
{ return ifa->sk->tbuf; }
|
||||||
|
@ -969,11 +993,13 @@ static inline void * ospf_tx_buffer(struct ospf_iface *ifa)
|
||||||
|
|
||||||
void ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn);
|
void ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn);
|
||||||
void ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr);
|
void ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n, ip_addr faddr);
|
||||||
|
uint ospf_hello3_options(struct ospf_packet *pkt);
|
||||||
|
|
||||||
/* dbdes.c */
|
/* dbdes.c */
|
||||||
void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n);
|
void ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n);
|
||||||
void ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n);
|
void ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n);
|
||||||
void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
|
void ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa, struct ospf_neighbor *n);
|
||||||
|
uint ospf_dbdes3_options(struct ospf_packet *pkt);
|
||||||
|
|
||||||
/* lsreq.c */
|
/* lsreq.c */
|
||||||
void ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n);
|
void ospf_send_lsreq(struct ospf_proto *p, struct ospf_neighbor *n);
|
||||||
|
|
|
@ -29,23 +29,24 @@ ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
|
||||||
pkt->areaid = htonl(ifa->oa->areaid);
|
pkt->areaid = htonl(ifa->oa->areaid);
|
||||||
pkt->checksum = 0;
|
pkt->checksum = 0;
|
||||||
pkt->instance_id = ifa->instance_id;
|
pkt->instance_id = ifa->instance_id;
|
||||||
pkt->autype = ifa->autype;
|
pkt->autype = ospf_is_v2(p) ? ifa->autype : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We assume OSPFv2 in ospf_pkt_finalize() */
|
/* We assume OSPFv2 in ospf_pkt_finalize() */
|
||||||
static void
|
static void
|
||||||
ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
|
ospf_pkt_finalize2(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
|
||||||
{
|
{
|
||||||
|
struct ospf_proto *p = ifa->oa->po;
|
||||||
struct password_item *pass = NULL;
|
struct password_item *pass = NULL;
|
||||||
union ospf_auth *auth = (void *) (pkt + 1);
|
union ospf_auth2 *auth = (void *) (pkt + 1);
|
||||||
|
memset(auth, 0, sizeof(union ospf_auth2));
|
||||||
pkt->checksum = 0;
|
|
||||||
pkt->autype = ifa->autype;
|
|
||||||
bzero(auth, sizeof(union ospf_auth));
|
|
||||||
|
|
||||||
/* Compatibility note: auth may contain anything if autype is
|
/* Compatibility note: auth may contain anything if autype is
|
||||||
none, but nonzero values do not work with Mikrotik OSPF */
|
none, but nonzero values do not work with Mikrotik OSPF */
|
||||||
|
|
||||||
|
pkt->checksum = 0;
|
||||||
|
pkt->autype = ifa->autype;
|
||||||
|
|
||||||
switch (ifa->autype)
|
switch (ifa->autype)
|
||||||
{
|
{
|
||||||
case OSPF_AUTH_SIMPLE:
|
case OSPF_AUTH_SIMPLE:
|
||||||
|
@ -60,7 +61,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
|
||||||
case OSPF_AUTH_NONE:
|
case OSPF_AUTH_NONE:
|
||||||
{
|
{
|
||||||
void *body = (void *) (auth + 1);
|
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_auth2);
|
||||||
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
|
pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -69,7 +70,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
|
||||||
pass = password_find(ifa->passwords, 0);
|
pass = password_find(ifa->passwords, 0);
|
||||||
if (!pass)
|
if (!pass)
|
||||||
{
|
{
|
||||||
log(L_ERR "No suitable password found for authentication");
|
log(L_ERR "%s: No suitable password found for authentication", p->p.name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,8 +106,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
|
||||||
else
|
else
|
||||||
memset32(auth_tail, HMAC_MAGIC, auth_len / 4);
|
memset32(auth_tail, HMAC_MAGIC, auth_len / 4);
|
||||||
|
|
||||||
mac_fill(pass->alg, pass->password, pass->length,
|
mac_fill(pass->alg, pass->password, pass->length, (byte *) pkt, *plen, auth_tail);
|
||||||
(byte *) pkt, *plen, auth_tail);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -114,13 +114,63 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
/* We assume OSPFv2 in ospf_pkt_checkauth() */
|
* Return an extra packet size that should be added to a final packet size
|
||||||
static int
|
*/
|
||||||
ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, uint len)
|
static void
|
||||||
|
ospf_pkt_finalize3(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen, ip_addr src)
|
||||||
{
|
{
|
||||||
struct ospf_proto *p = ifa->oa->po;
|
struct ospf_proto *p = ifa->oa->po;
|
||||||
union ospf_auth *auth = (void *) (pkt + 1);
|
struct ospf_auth3 *auth = (void *) ((byte *) pkt + *plen);
|
||||||
|
|
||||||
|
pkt->checksum = 0;
|
||||||
|
pkt->autype = 0;
|
||||||
|
|
||||||
|
if (ifa->autype != OSPF_AUTH_CRYPT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct password_item *pass = password_find(ifa->passwords, 0);
|
||||||
|
if (!pass)
|
||||||
|
{
|
||||||
|
log(L_ERR "%s: No suitable password found for authentication", p->p.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: Ensure persistence */
|
||||||
|
p->csn64++;
|
||||||
|
|
||||||
|
uint mac_len = mac_type_length(pass->alg);
|
||||||
|
uint auth_len = sizeof(struct ospf_auth3) + mac_len;
|
||||||
|
*plen += auth_len;
|
||||||
|
|
||||||
|
ASSERT(*plen < ifa->sk->tbsize);
|
||||||
|
|
||||||
|
memset(auth, 0, sizeof(struct ospf_auth3));
|
||||||
|
auth->type = htons(OSPF3_AUTH_HMAC);
|
||||||
|
auth->length = htons(auth_len);
|
||||||
|
auth->reserved = 0;
|
||||||
|
auth->sa_id = htons(pass->id);
|
||||||
|
put_u64(&auth->csn, p->csn64);
|
||||||
|
|
||||||
|
/* Initialize with src IP address padded with HMAC_MAGIC */
|
||||||
|
put_ip6(auth->data, ipa_to_ip6(src));
|
||||||
|
memset32(auth->data + 16, HMAC_MAGIC, (mac_len - 16) / 4);
|
||||||
|
|
||||||
|
/* Attach OSPFv3 Cryptographic Protocol ID to the key */
|
||||||
|
uint pass_len = pass->length + 2;
|
||||||
|
byte *pass_key = alloca(pass_len);
|
||||||
|
memcpy(pass_key, pass->password, pass->length);
|
||||||
|
put_u16(pass_key + pass->length, OSPF3_CRYPTO_ID);
|
||||||
|
|
||||||
|
mac_fill(pass->alg, pass_key, pass_len, (byte *) pkt, *plen, auth->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ospf_pkt_checkauth2(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, uint len)
|
||||||
|
{
|
||||||
|
struct ospf_proto *p = ifa->oa->po;
|
||||||
|
union ospf_auth2 *auth = (void *) (pkt + 1);
|
||||||
struct password_item *pass = NULL;
|
struct password_item *pass = NULL;
|
||||||
const char *err_dsc = NULL;
|
const char *err_dsc = NULL;
|
||||||
uint err_val = 0;
|
uint err_val = 0;
|
||||||
|
@ -200,6 +250,119 @@ drop:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ospf_pkt_checkauth3(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, uint len, ip_addr src)
|
||||||
|
{
|
||||||
|
struct ospf_proto *p = ifa->oa->po;
|
||||||
|
const char *err_dsc = NULL;
|
||||||
|
uint err_val = 0;
|
||||||
|
|
||||||
|
uint plen = ntohs(pkt->length);
|
||||||
|
uint opts, lls_present, auth_present;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When autentication is not enabled, ignore the trailer. This is different
|
||||||
|
* from OSPFv2, but it is necessary in order to support migration modes. Note
|
||||||
|
* that regular authenticated packets do not have valid checksum and will be
|
||||||
|
* dropped by OS on non-authenticated ifaces.
|
||||||
|
*/
|
||||||
|
if (ifa->autype != OSPF_AUTH_CRYPT)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
switch(pkt->type)
|
||||||
|
{
|
||||||
|
case HELLO_P:
|
||||||
|
opts = ospf_hello3_options(pkt);
|
||||||
|
lls_present = opts & OPT_L_V3;
|
||||||
|
auth_present = opts & OPT_AT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DBDES_P:
|
||||||
|
opts = ospf_dbdes3_options(pkt);
|
||||||
|
lls_present = opts & OPT_L_V3;
|
||||||
|
auth_present = opts & OPT_AT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
lls_present = 0;
|
||||||
|
auth_present = n->options & OPT_AT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!auth_present)
|
||||||
|
DROP1("missing authentication trailer");
|
||||||
|
|
||||||
|
if (lls_present)
|
||||||
|
{
|
||||||
|
if ((plen + sizeof(struct ospf_lls)) > len)
|
||||||
|
DROP("packet length mismatch", len);
|
||||||
|
|
||||||
|
struct ospf_lls *lls = (void *) ((byte *) pkt + plen);
|
||||||
|
plen += ntohs(lls->length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((plen + sizeof(struct ospf_auth3)) > len)
|
||||||
|
DROP("packet length mismatch", len);
|
||||||
|
|
||||||
|
struct ospf_auth3 *auth = (void *) ((byte *) pkt + plen);
|
||||||
|
|
||||||
|
uint rcv_auth_type = ntohs(auth->type);
|
||||||
|
if (rcv_auth_type != OSPF3_AUTH_HMAC)
|
||||||
|
DROP("authentication method mismatch", rcv_auth_type);
|
||||||
|
|
||||||
|
uint rcv_auth_len = ntohs(auth->length);
|
||||||
|
if (plen + rcv_auth_len > len)
|
||||||
|
DROP("packet length mismatch", len);
|
||||||
|
|
||||||
|
uint rcv_key_id = ntohs(auth->sa_id);
|
||||||
|
struct password_item *pass = password_find_by_id(ifa->passwords, rcv_key_id);
|
||||||
|
if (!pass)
|
||||||
|
DROP("no suitable password found", rcv_key_id);
|
||||||
|
|
||||||
|
uint mac_len = mac_type_length(pass->alg);
|
||||||
|
if (rcv_auth_len != (sizeof(struct ospf_auth3) + mac_len))
|
||||||
|
DROP("wrong authentication length", rcv_auth_len);
|
||||||
|
|
||||||
|
uint pt = pkt->type - 1;
|
||||||
|
u64 rcv_csn = get_u64(&auth->csn);
|
||||||
|
if (n && (rcv_csn <= n->csn64[pt]))
|
||||||
|
{
|
||||||
|
/* We want to report both new and old CSN */
|
||||||
|
LOG_PKT_AUTH("Authentication failed for nbr %R on %s - "
|
||||||
|
"lower sequence number (rcv %u, old %u)",
|
||||||
|
n->rid, ifa->ifname, (uint) rcv_csn, (uint) n->csn64[pt]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the received authentication data */
|
||||||
|
byte *auth_data = alloca(mac_len);
|
||||||
|
memcpy(auth_data, auth->data, mac_len);
|
||||||
|
|
||||||
|
/* Initialize with src IP address padded with HMAC_MAGIC */
|
||||||
|
put_ip6(auth->data, ipa_to_ip6(src));
|
||||||
|
memset32(auth->data + 16, HMAC_MAGIC, (mac_len - 16) / 4);
|
||||||
|
|
||||||
|
/* Attach OSPFv3 Cryptographic Protocol ID to the key */
|
||||||
|
uint pass_len = pass->length + 2;
|
||||||
|
byte *pass_key = alloca(pass_len);
|
||||||
|
memcpy(pass_key, pass->password, pass->length);
|
||||||
|
put_u16(pass_key + pass->length, OSPF3_CRYPTO_ID);
|
||||||
|
|
||||||
|
if (!mac_verify(pass->alg, pass_key, pass_len,
|
||||||
|
(byte *) pkt, plen + rcv_auth_len, auth_data))
|
||||||
|
DROP("wrong authentication code", pass->id);
|
||||||
|
|
||||||
|
if (n)
|
||||||
|
n->csn64[pt] = rcv_csn;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
LOG_PKT_AUTH("Authentication failed for nbr %R on %s - %s (%u)",
|
||||||
|
(n ? n->rid : ntohl(pkt->routerid)), ifa->ifname, err_dsc, err_val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ospf_rx_hook
|
* ospf_rx_hook
|
||||||
* @sk: socket we received the packet.
|
* @sk: socket we received the packet.
|
||||||
|
@ -298,12 +461,12 @@ ospf_rx_hook(sock *sk, uint len)
|
||||||
|
|
||||||
if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT))
|
if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT))
|
||||||
{
|
{
|
||||||
uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
|
uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth2);
|
||||||
uint blen = plen - hlen;
|
uint blen = plen - hlen;
|
||||||
void *body = ((void *) pkt) + hlen;
|
void *body = ((void *) pkt) + hlen;
|
||||||
|
|
||||||
if (!ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
|
if (!ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
|
||||||
DROP1("invalid checksum");
|
DROP("invalid checksum", ntohs(pkt->checksum));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Third, we resolve associated iface and handle vlinks. */
|
/* Third, we resolve associated iface and handle vlinks. */
|
||||||
|
@ -401,8 +564,14 @@ found:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check packet type here, ospf_pkt_checkauth3() expects valid values */
|
||||||
|
if (pkt->type < HELLO_P || pkt->type > LSACK_P)
|
||||||
|
DROP("invalid packet type", pkt->type);
|
||||||
|
|
||||||
/* ospf_pkt_checkauth() has its own error logging */
|
/* ospf_pkt_checkauth() has its own error logging */
|
||||||
if (ospf_is_v2(p) && !ospf_pkt_checkauth(n, ifa, pkt, len))
|
if ((ospf_is_v2(p) ?
|
||||||
|
!ospf_pkt_checkauth2(n, ifa, pkt, len) :
|
||||||
|
!ospf_pkt_checkauth3(n, ifa, pkt, len, sk->faddr)))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
switch (pkt->type)
|
switch (pkt->type)
|
||||||
|
@ -426,9 +595,6 @@ found:
|
||||||
case LSACK_P:
|
case LSACK_P:
|
||||||
ospf_receive_lsack(pkt, ifa, n);
|
ospf_receive_lsack(pkt, ifa, n);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
DROP("invalid packet type", pkt->type);
|
|
||||||
};
|
};
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -472,7 +638,9 @@ ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
|
||||||
uint plen = ntohs(pkt->length);
|
uint plen = ntohs(pkt->length);
|
||||||
|
|
||||||
if (ospf_is_v2(ifa->oa->po))
|
if (ospf_is_v2(ifa->oa->po))
|
||||||
ospf_pkt_finalize(ifa, pkt, &plen);
|
ospf_pkt_finalize2(ifa, pkt, &plen);
|
||||||
|
else
|
||||||
|
ospf_pkt_finalize3(ifa, pkt, &plen, sk->saddr);
|
||||||
|
|
||||||
int done = sk_send_to(sk, plen, dst, 0);
|
int done = sk_send_to(sk, plen, dst, 0);
|
||||||
if (!done)
|
if (!done)
|
||||||
|
|
Loading…
Reference in a new issue