Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nhrpd: add cisco-authentication password support #16172

Merged
merged 2 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions doc/user/nhrpd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ Configuring NHRP
registration requests are sent. By default registrations are sent every one
third of the holdtime.

.. clicmd:: ip nhrp authentication PASSWORD

Enables Cisco style authentication on NHRP packets. This embeds the
plaintext password to the outgoing NHRP packets.
Maximum length of the password is 8 characters.

.. clicmd:: ip nhrp map A.B.C.D|X:X::X:X A.B.C.D|local

Map an IP address of a station to the station's NBMA address.
Expand Down
2 changes: 2 additions & 0 deletions nhrpd/nhrp_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ static int nhrp_if_delete_hook(struct interface *ifp)
free(nifp->ipsec_fallback_profile);
if (nifp->source)
free(nifp->source);
if (nifp->auth_token)
zbuf_free(nifp->auth_token);

XFREE(MTYPE_NHRP_IF, ifp->info);
return 0;
Expand Down
4 changes: 2 additions & 2 deletions nhrpd/nhrp_nhs.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ static void nhrp_reg_send_req(struct event *t)
cie->holding_time = htons(if_ad->holdtime);
cie->mtu = htons(if_ad->mtu);

nhrp_ext_request(zb, hdr, ifp);
nhrp_ext_request(zb, hdr);

/* Cisco NAT detection extension */
if (sockunion_family(&r->proto_addr) != AF_UNSPEC) {
Expand All @@ -240,7 +240,7 @@ static void nhrp_reg_send_req(struct event *t)
cie->mtu = htons(if_ad->mtu);
nhrp_ext_complete(zb, ext);

nhrp_packet_complete(zb, hdr);
nhrp_packet_complete(zb, hdr, ifp);
nhrp_peer_send(r->peer, zb);
zbuf_free(zb);
}
Expand Down
27 changes: 22 additions & 5 deletions nhrpd/nhrp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,32 @@ uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len)
return (~csum) & 0xffff;
}

void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr)
void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr,
struct interface *ifp)
{
nhrp_packet_complete_auth(zb, hdr, ifp, true);
}

void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr,
struct interface *ifp, bool auth)
{
struct nhrp_interface *nifp = ifp->info;
struct zbuf *auth_token = nifp->auth_token;
struct nhrp_extension_header *dst;
unsigned short size;

if (auth && auth_token) {
dst = nhrp_ext_push(zb, hdr,
NHRP_EXTENSION_AUTHENTICATION |
NHRP_EXTENSION_FLAG_COMPULSORY);
zbuf_copy_peek(zb, auth_token, zbuf_size(auth_token));
nhrp_ext_complete(zb, dst);
}

if (hdr->extension_offset)
nhrp_ext_push(zb, hdr,
NHRP_EXTENSION_END
| NHRP_EXTENSION_FLAG_COMPULSORY);
NHRP_EXTENSION_END |
NHRP_EXTENSION_FLAG_COMPULSORY);

size = zb->tail - (uint8_t *)hdr;
hdr->packet_size = htons(size);
Expand Down Expand Up @@ -225,8 +243,7 @@ struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb,
return ext;
}

void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr,
struct interface *ifp)
void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr)
{
/* Place holders for standard extensions */
nhrp_ext_push(zb, hdr,
Expand Down
105 changes: 91 additions & 14 deletions nhrpd/nhrp_peer.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp)
break;
}
}
nhrp_packet_complete(zb, hdr);
nhrp_packet_complete(zb, hdr, ifp);
nhrp_peer_send(peer, zb);
err:
nhrp_peer_unref(peer);
Expand Down Expand Up @@ -730,7 +730,8 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p)
}
}

nhrp_packet_complete(zb, hdr);
/* auth ext was validated and copied from the request */
nhrp_packet_complete_auth(zb, hdr, ifp, false);
nhrp_peer_send(p->peer, zb);
err:
zbuf_free(zb);
Expand Down Expand Up @@ -812,7 +813,7 @@ void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type,

/* Payload is the packet causing indication */
zbuf_copy(zb, pkt, zbuf_used(pkt));
nhrp_packet_complete(zb, hdr);
nhrp_packet_complete(zb, hdr, ifp);
nhrp_peer_send(p, zb);
nhrp_peer_unref(p);
zbuf_free(zb);
Expand Down Expand Up @@ -1063,7 +1064,7 @@ static void nhrp_peer_forward(struct nhrp_peer *p,
nhrp_ext_complete(zb, dst);
}

nhrp_packet_complete(zb, hdr);
nhrp_packet_complete_auth(zb, hdr, pp->ifp, false);
nhrp_peer_send(p, zb);
zbuf_free(zb);
zbuf_free(zb_copy);
Expand All @@ -1089,8 +1090,7 @@ static void nhrp_packet_debug(struct zbuf *zb, const char *dir)

reply = packet_types[hdr->type].type == PACKET_REPLY;
debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %pSU -> %pSU", dir,
(packet_types[hdr->type].name ? packet_types[hdr->type].name
: "Unknown"),
(packet_types[hdr->type].name ? : "Unknown"),
hdr->type, reply ? &dst_proto : &src_proto,
reply ? &src_proto : &dst_proto);
}
Expand All @@ -1106,11 +1106,78 @@ static int proto2afi(uint16_t proto)
return AF_UNSPEC;
}

struct nhrp_route_info {
int local;
struct interface *ifp;
struct nhrp_vc *vc;
};
static int nhrp_packet_send_error(struct nhrp_packet_parser *pp,
uint16_t indication_code, uint16_t offset)
{
union sockunion src_proto, dst_proto;
struct nhrp_packet_header *hdr;
struct zbuf *zb;

src_proto = pp->src_proto;
dst_proto = pp->dst_proto;
if (packet_types[pp->hdr->type].type != PACKET_REPLY) {
src_proto = pp->dst_proto;
dst_proto = pp->src_proto;
}
/* Create reply */
zb = zbuf_alloc(1500);
hdr = nhrp_packet_push(zb, NHRP_PACKET_ERROR_INDICATION, &pp->src_nbma,
&src_proto, &dst_proto);

hdr->u.error.code = htons(indication_code);
hdr->u.error.offset = htons(offset);
hdr->flags = pp->hdr->flags;
hdr->hop_count = 0; /* XXX: cisco returns 255 */

/* Payload is the packet causing error */
/* Don`t add extension according to RFC */
zbuf_put(zb, pp->hdr, sizeof(*pp->hdr));
zbuf_put(zb, sockunion_get_addr(&pp->src_nbma),
hdr->src_nbma_address_len);
zbuf_put(zb, sockunion_get_addr(&pp->src_proto),
hdr->src_protocol_address_len);
zbuf_put(zb, sockunion_get_addr(&pp->dst_proto),
hdr->dst_protocol_address_len);
nhrp_packet_complete_auth(zb, hdr, pp->ifp, false);

nhrp_peer_send(pp->peer, zb);
zbuf_free(zb);
return 0;
}

static bool nhrp_connection_authorized(struct nhrp_packet_parser *pp)
{
struct nhrp_cisco_authentication_extension *auth_ext;
struct nhrp_interface *nifp = pp->ifp->info;
struct zbuf *auth = nifp->auth_token;
struct nhrp_extension_header *ext;
struct zbuf *extensions, pl;
int cmp = 1;

dleroy marked this conversation as resolved.
Show resolved Hide resolved
extensions = zbuf_alloc(zbuf_used(&pp->extensions));
zbuf_copy_peek(extensions, &pp->extensions, zbuf_used(&pp->extensions));
while ((ext = nhrp_ext_pull(extensions, &pl)) != NULL) {
switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) {
case NHRP_EXTENSION_AUTHENTICATION:
dleroy marked this conversation as resolved.
Show resolved Hide resolved
cmp = memcmp(auth->buf, pl.buf, zbuf_size(auth));
auth_ext = (struct nhrp_cisco_authentication_extension *)
auth->buf;
debugf(NHRP_DEBUG_COMMON,
"Processing Authentication Extension for (%s:%s|%d)",
auth_ext->secret,
((struct nhrp_cisco_authentication_extension *)
pl.buf)
->secret,
cmp);
break;
default:
/* Ignoring all received extensions except Authentication*/
break;
}
}
zbuf_free(extensions);
return cmp == 0;
}

void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb)
{
Expand Down Expand Up @@ -1191,10 +1258,20 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb)
goto drop;
}

/* RFC2332 5.3.4 - Authentication is always done pairwise on an NHRP
* hop-by-hop basis; i.e. regenerated at each hop. */
nhrp_packet_debug(zb, "Recv");

/* FIXME: Check authentication here. This extension needs to be
* pre-handled. */
if (nifp->auth_token &&
(hdr->type != NHRP_PACKET_ERROR_INDICATION ||
hdr->u.error.code != NHRP_ERROR_AUTHENTICATION_FAILURE)) {
if (!nhrp_connection_authorized(&pp)) {
nhrp_packet_send_error(&pp,
NHRP_ERROR_AUTHENTICATION_FAILURE,
0);
info = "authentication failure";
goto drop;
}
}

/* Figure out if this is local */
target_addr = (packet_types[hdr->type].type == PACKET_REPLY)
Expand Down
4 changes: 2 additions & 2 deletions nhrpd/nhrp_shortcut.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
"Shortcut res_req: set cie ht to %u and mtu to %u. shortcut ht is %u",
ntohs(cie->holding_time), ntohs(cie->mtu), s->holding_time);

nhrp_ext_request(zb, hdr, ifp);
nhrp_ext_request(zb, hdr);

/* Cisco NAT detection extension */
hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT);
Expand All @@ -438,7 +438,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s)
nhrp_ext_complete(zb, ext);
}

nhrp_packet_complete(zb, hdr);
nhrp_packet_complete(zb, hdr, ifp);

nhrp_peer_send(peer, zb);
nhrp_peer_unref(peer);
Expand Down
62 changes: 62 additions & 0 deletions nhrpd/nhrp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

#include "nhrpd.h"
#include "netlink.h"
#include "nhrp_protocol.h"

#include "nhrpd/nhrp_vty_clippy.c"

static int nhrp_config_write(struct vty *vty);
static struct cmd_node zebra_node = {
Expand Down Expand Up @@ -459,6 +462,55 @@ DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd,
return CMD_SUCCESS;
}

#define NHRP_CISCO_PASS_LEN 8
DEFPY(if_nhrp_authentication, if_nhrp_authentication_cmd,
AFI_CMD "nhrp authentication PASSWORD$password",
AFI_STR
NHRP_STR
"Specify plain text password used for authenticantion\n"
"Password, plain text, limited to 8 characters\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct nhrp_cisco_authentication_extension *auth;
struct nhrp_interface *nifp = ifp->info;
int pass_len = strlen(password);

if (pass_len > NHRP_CISCO_PASS_LEN) {
vty_out(vty, "Password size limit exceeded (%d>%d)\n",
pass_len, NHRP_CISCO_PASS_LEN);
return CMD_WARNING_CONFIG_FAILED;
}

if (nifp->auth_token)
zbuf_free(nifp->auth_token);

nifp->auth_token = zbuf_alloc(pass_len + sizeof(uint32_t));
auth = (struct nhrp_cisco_authentication_extension *)
nifp->auth_token->buf;
auth->type = htonl(NHRP_AUTHENTICATION_PLAINTEXT);
memcpy(auth->secret, password, pass_len);

return CMD_SUCCESS;
}


DEFPY(if_no_nhrp_authentication, if_no_nhrp_authentication_cmd,
"no " AFI_CMD "nhrp authentication PASSWORD$password",
dleroy marked this conversation as resolved.
Show resolved Hide resolved
NO_STR
AFI_STR
NHRP_STR
"Specify plain text password used for authenticantion\n"
"Password, plain text, limited to 8 characters\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct nhrp_interface *nifp = ifp->info;
dleroy marked this conversation as resolved.
Show resolved Hide resolved

if (nifp->auth_token)
zbuf_free(nifp->auth_token);
return CMD_SUCCESS;
}


DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd,
"ip nhrp mtu <(576-1500)|opennhrp>",
IP_STR
Expand Down Expand Up @@ -1053,6 +1105,7 @@ DEFUN(show_dmvpn, show_dmvpn_cmd,
static void clear_nhrp_cache(struct nhrp_cache *c, void *data)
{
struct info_ctx *ctx = data;

if (c->cur.type <= NHRP_CACHE_DYNAMIC) {
nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL,
NULL);
Expand Down Expand Up @@ -1129,6 +1182,7 @@ static void interface_config_write_nhrp_map(struct nhrp_cache_config *c,
static int interface_config_write(struct vty *vty)
{
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
struct nhrp_cisco_authentication_extension *auth;
struct write_map_ctx mapctx;
struct interface *ifp;
struct nhrp_interface *nifp;
Expand All @@ -1155,6 +1209,12 @@ static int interface_config_write(struct vty *vty)
if (nifp->source)
vty_out(vty, " tunnel source %s\n", nifp->source);

if (nifp->auth_token) {
auth = (struct nhrp_cisco_authentication_extension *)
nifp->auth_token->buf;
vty_out(vty, " ip nhrp authentication %s\n", auth->secret);
}

for (afi = 0; afi < AFI_MAX; afi++) {
struct nhrp_afi_data *ad = &nifp->afi[afi];

Expand Down Expand Up @@ -1256,6 +1316,8 @@ void nhrp_config_init(void)
install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd);
install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd);
install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd);
install_element(INTERFACE_NODE, &if_nhrp_authentication_cmd);
install_element(INTERFACE_NODE, &if_no_nhrp_authentication_cmd);
install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd);
install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd);
install_element(INTERFACE_NODE, &if_nhrp_flags_cmd);
Expand Down
10 changes: 7 additions & 3 deletions nhrpd/nhrpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ DECLARE_DLIST(nhrp_reglist, struct nhrp_registration, reglist_entry);
struct nhrp_interface {
struct interface *ifp;

struct zbuf *auth_token;
unsigned enabled : 1;

char *ipsec_profile, *ipsec_fallback_profile, *source;
Expand Down Expand Up @@ -480,9 +481,13 @@ struct nhrp_packet_header *nhrp_packet_push(struct zbuf *zb, uint8_t type,
const union sockunion *src_nbma,
const union sockunion *src_proto,
const union sockunion *dst_proto);
void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr);
uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len);

void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr,
struct interface *ifp);
void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr,
struct interface *ifp, bool auth);

struct nhrp_packet_header *nhrp_packet_pull(struct zbuf *zb,
union sockunion *src_nbma,
union sockunion *src_proto,
Expand All @@ -501,8 +506,7 @@ nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type);
void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext);
struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb,
struct zbuf *payload);
void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr,
struct interface *);
void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr);
int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr,
struct interface *ifp, struct nhrp_extension_header *ext,
struct zbuf *extpayload);
Expand Down
Loading
Loading