mirror of
https://github.com/systemd/systemd.git
synced 2025-03-11 20:58:27 +03:00
sd-ndisc: add basic support of Redirect message
This makes sd-ndisc support Redirect message defined in RFC 4861.
This commit is contained in:
parent
b03d7291d5
commit
44e8cf303b
@ -43,6 +43,7 @@ int icmp6_bind(int ifindex, bool is_router) {
|
||||
};
|
||||
ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
|
||||
ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter);
|
||||
ICMP6_FILTER_SETPASS(ND_REDIRECT, &filter);
|
||||
}
|
||||
|
||||
s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
|
||||
|
@ -29,6 +29,7 @@ sources = files(
|
||||
'sd-lldp-tx.c',
|
||||
'sd-ndisc.c',
|
||||
'sd-ndisc-neighbor.c',
|
||||
'sd-ndisc-redirect.c',
|
||||
'sd-ndisc-router.c',
|
||||
'sd-radv.c',
|
||||
)
|
||||
|
21
src/libsystemd-network/ndisc-redirect-internal.h
Normal file
21
src/libsystemd-network/ndisc-redirect-internal.h
Normal file
@ -0,0 +1,21 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
#include "icmp6-packet.h"
|
||||
#include "set.h"
|
||||
|
||||
struct sd_ndisc_redirect {
|
||||
unsigned n_ref;
|
||||
|
||||
ICMP6Packet *packet;
|
||||
|
||||
struct in6_addr target_address;
|
||||
struct in6_addr destination_address;
|
||||
|
||||
Set *options;
|
||||
};
|
||||
|
||||
sd_ndisc_redirect* ndisc_redirect_new(ICMP6Packet *packet);
|
||||
int ndisc_redirect_parse(sd_ndisc *nd, sd_ndisc_redirect *rd);
|
123
src/libsystemd-network/sd-ndisc-redirect.c
Normal file
123
src/libsystemd-network/sd-ndisc-redirect.c
Normal file
@ -0,0 +1,123 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <netinet/icmp6.h>
|
||||
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "ndisc-internal.h"
|
||||
#include "ndisc-option.h"
|
||||
#include "ndisc-redirect-internal.h"
|
||||
|
||||
static sd_ndisc_redirect* ndisc_redirect_free(sd_ndisc_redirect *rd) {
|
||||
if (!rd)
|
||||
return NULL;
|
||||
|
||||
icmp6_packet_unref(rd->packet);
|
||||
set_free(rd->options);
|
||||
return mfree(rd);
|
||||
}
|
||||
|
||||
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_ndisc_redirect, sd_ndisc_redirect, ndisc_redirect_free);
|
||||
|
||||
sd_ndisc_redirect* ndisc_redirect_new(ICMP6Packet *packet) {
|
||||
sd_ndisc_redirect *rd;
|
||||
|
||||
assert(packet);
|
||||
|
||||
rd = new(sd_ndisc_redirect, 1);
|
||||
if (!rd)
|
||||
return NULL;
|
||||
|
||||
*rd = (sd_ndisc_redirect) {
|
||||
.n_ref = 1,
|
||||
.packet = icmp6_packet_ref(packet),
|
||||
};
|
||||
|
||||
return rd;
|
||||
}
|
||||
|
||||
int ndisc_redirect_parse(sd_ndisc *nd, sd_ndisc_redirect *rd) {
|
||||
int r;
|
||||
|
||||
assert(rd);
|
||||
assert(rd->packet);
|
||||
|
||||
if (rd->packet->raw_size < sizeof(struct nd_redirect))
|
||||
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Too small to be a redirect message, ignoring.");
|
||||
|
||||
const struct nd_redirect *a = (const struct nd_redirect*) rd->packet->raw_packet;
|
||||
assert(a->nd_rd_type == ND_REDIRECT);
|
||||
assert(a->nd_rd_code == 0);
|
||||
|
||||
rd->target_address = a->nd_rd_target;
|
||||
rd->destination_address = a->nd_rd_dst;
|
||||
|
||||
if (in6_addr_is_null(&rd->target_address) || in6_addr_is_multicast(&rd->target_address))
|
||||
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received Redirect message with an invalid target address, ignoring datagram: %m");
|
||||
|
||||
if (in6_addr_is_null(&rd->destination_address) || in6_addr_is_multicast(&rd->destination_address))
|
||||
return log_ndisc_errno(nd, SYNTHETIC_ERRNO(EBADMSG),
|
||||
"Received Redirect message with an invalid destination address, ignoring datagram: %m");
|
||||
|
||||
r = ndisc_parse_options(rd->packet, &rd->options);
|
||||
if (r < 0)
|
||||
return log_ndisc_errno(nd, r, "Failed to parse NDisc options in Redirect message, ignoring datagram: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ndisc_redirect_set_sender_address(sd_ndisc_redirect *rd, const struct in6_addr *addr) {
|
||||
assert_return(rd, -EINVAL);
|
||||
|
||||
return icmp6_packet_set_sender_address(rd->packet, addr);
|
||||
}
|
||||
|
||||
int sd_ndisc_redirect_get_sender_address(sd_ndisc_redirect *rd, struct in6_addr *ret) {
|
||||
assert_return(rd, -EINVAL);
|
||||
|
||||
return icmp6_packet_get_sender_address(rd->packet, ret);
|
||||
}
|
||||
|
||||
int sd_ndisc_redirect_get_target_address(sd_ndisc_redirect *rd, struct in6_addr *ret) {
|
||||
assert_return(rd, -EINVAL);
|
||||
|
||||
if (in6_addr_is_null(&rd->target_address))
|
||||
return -ENODATA;
|
||||
|
||||
if (ret)
|
||||
*ret = rd->target_address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ndisc_redirect_get_destination_address(sd_ndisc_redirect *rd, struct in6_addr *ret) {
|
||||
assert_return(rd, -EINVAL);
|
||||
|
||||
if (in6_addr_is_null(&rd->destination_address))
|
||||
return -ENODATA;
|
||||
|
||||
if (ret)
|
||||
*ret = rd->destination_address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_ndisc_redirect_get_target_mac(sd_ndisc_redirect *rd, struct ether_addr *ret) {
|
||||
assert_return(rd, -EINVAL);
|
||||
|
||||
return ndisc_option_get_mac(rd->options, SD_NDISC_OPTION_TARGET_LL_ADDRESS, ret);
|
||||
}
|
||||
|
||||
int sd_ndisc_redirect_get_redirected_header(sd_ndisc_redirect *rd, struct ip6_hdr *ret) {
|
||||
assert_return(rd, -EINVAL);
|
||||
|
||||
sd_ndisc_option *p = ndisc_option_get_by_type(rd->options, SD_NDISC_OPTION_REDIRECTED_HEADER);
|
||||
if (!p)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret)
|
||||
*ret = p->hdr;
|
||||
return 0;
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
#include "memory-util.h"
|
||||
#include "ndisc-internal.h"
|
||||
#include "ndisc-neighbor-internal.h"
|
||||
#include "ndisc-redirect-internal.h"
|
||||
#include "ndisc-router-internal.h"
|
||||
#include "network-common.h"
|
||||
#include "random-util.h"
|
||||
@ -30,6 +31,7 @@ static const char * const ndisc_event_table[_SD_NDISC_EVENT_MAX] = {
|
||||
[SD_NDISC_EVENT_TIMEOUT] = "timeout",
|
||||
[SD_NDISC_EVENT_ROUTER] = "router",
|
||||
[SD_NDISC_EVENT_NEIGHBOR] = "neighbor",
|
||||
[SD_NDISC_EVENT_REDIRECT] = "redirect",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(ndisc_event, sd_ndisc_event_t);
|
||||
@ -257,6 +259,35 @@ static int ndisc_handle_neighbor(sd_ndisc *nd, ICMP6Packet *packet) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_handle_redirect(sd_ndisc *nd, ICMP6Packet *packet) {
|
||||
_cleanup_(sd_ndisc_redirect_unrefp) sd_ndisc_redirect *rd = NULL;
|
||||
struct in6_addr a;
|
||||
int r;
|
||||
|
||||
assert(nd);
|
||||
assert(packet);
|
||||
|
||||
rd = ndisc_redirect_new(packet);
|
||||
if (!rd)
|
||||
return -ENOMEM;
|
||||
|
||||
r = ndisc_redirect_parse(nd, rd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_ndisc_redirect_get_sender_address(rd, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_ndisc(nd, "Received Redirect message from %s: Target=%s, Destination=%s",
|
||||
IN6_ADDR_TO_STRING(&a),
|
||||
IN6_ADDR_TO_STRING(&rd->target_address),
|
||||
IN6_ADDR_TO_STRING(&rd->destination_address));
|
||||
|
||||
ndisc_callback(nd, SD_NDISC_EVENT_REDIRECT, rd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
_cleanup_(icmp6_packet_unrefp) ICMP6Packet *packet = NULL;
|
||||
sd_ndisc *nd = ASSERT_PTR(userdata);
|
||||
@ -298,6 +329,10 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda
|
||||
(void) ndisc_handle_neighbor(nd, packet);
|
||||
break;
|
||||
|
||||
case ND_REDIRECT:
|
||||
(void) ndisc_handle_redirect(nd, packet);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_ndisc(nd, "Received an ICMPv6 packet with unexpected type %i, ignoring.", r);
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ _not_installed_headers = [
|
||||
'sd-ndisc.h',
|
||||
'sd-ndisc-neighbor.h',
|
||||
'sd-ndisc-protocol.h',
|
||||
'sd-ndisc-redirect.h',
|
||||
'sd-ndisc-router.h',
|
||||
'sd-netlink.h',
|
||||
'sd-network.h',
|
||||
|
46
src/systemd/sd-ndisc-redirect.h
Normal file
46
src/systemd/sd-ndisc-redirect.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosdndiscredirectfoo
|
||||
#define foosdndiscredirectfoo
|
||||
|
||||
/***
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
typedef struct sd_ndisc_redirect sd_ndisc_redirect;
|
||||
|
||||
sd_ndisc_redirect* sd_ndisc_redirect_ref(sd_ndisc_redirect *na);
|
||||
sd_ndisc_redirect* sd_ndisc_redirect_unref(sd_ndisc_redirect *na);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_redirect, sd_ndisc_redirect_unref);
|
||||
|
||||
int sd_ndisc_redirect_set_sender_address(sd_ndisc_redirect *rd, const struct in6_addr *addr);
|
||||
int sd_ndisc_redirect_get_sender_address(sd_ndisc_redirect *na, struct in6_addr *ret);
|
||||
int sd_ndisc_redirect_get_target_address(sd_ndisc_redirect *na, struct in6_addr *ret);
|
||||
int sd_ndisc_redirect_get_destination_address(sd_ndisc_redirect *na, struct in6_addr *ret);
|
||||
int sd_ndisc_redirect_get_target_mac(sd_ndisc_redirect *na, struct ether_addr *ret);
|
||||
int sd_ndisc_redirect_get_redirected_header(sd_ndisc_redirect *na, struct ip6_hdr *ret);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
@ -28,6 +28,7 @@
|
||||
#include "sd-event.h"
|
||||
#include "sd-ndisc-neighbor.h"
|
||||
#include "sd-ndisc-protocol.h"
|
||||
#include "sd-ndisc-redirect.h"
|
||||
#include "sd-ndisc-router.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
@ -40,6 +41,7 @@ __extension__ typedef enum sd_ndisc_event_t {
|
||||
SD_NDISC_EVENT_TIMEOUT,
|
||||
SD_NDISC_EVENT_ROUTER,
|
||||
SD_NDISC_EVENT_NEIGHBOR,
|
||||
SD_NDISC_EVENT_REDIRECT,
|
||||
_SD_NDISC_EVENT_MAX,
|
||||
_SD_NDISC_EVENT_INVALID = -EINVAL,
|
||||
_SD_ENUM_FORCE_S64(NDISC_EVENT)
|
||||
|
Loading…
x
Reference in New Issue
Block a user