1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use futures::stream::StreamExt;
use netlink_packet_route::{
constants::*,
neighbour::{NeighbourMessage, Nla},
NetlinkPayload,
RtnlMessage,
};
use netlink_proto::packet::NetlinkMessage;
use crate::{Error, Handle};
use std::net::IpAddr;
pub struct NeighbourAddRequest {
handle: Handle,
message: NeighbourMessage,
replace: bool,
}
impl NeighbourAddRequest {
pub(crate) fn new(handle: Handle, index: u32, destination: IpAddr) -> Self {
let mut message = NeighbourMessage::default();
message.header.family = match destination {
IpAddr::V4(_) => AF_INET as u8,
IpAddr::V6(_) => AF_INET6 as u8,
};
message.header.ifindex = index;
message.header.state = IFA_F_PERMANENT as u16;
message.header.ntype = NDA_UNSPEC as u8;
message.nlas.push(Nla::Destination(match destination {
IpAddr::V4(v4) => v4.octets().to_vec(),
IpAddr::V6(v6) => v6.octets().to_vec(),
}));
NeighbourAddRequest {
handle,
message,
replace: false,
}
}
pub(crate) fn new_bridge(handle: Handle, index: u32, lla: &[u8]) -> Self {
let mut message = NeighbourMessage::default();
message.header.family = AF_BRIDGE as u8;
message.header.ifindex = index;
message.header.state = NUD_PERMANENT;
message.header.ntype = NDA_UNSPEC as u8;
message.nlas.push(Nla::LinkLocalAddress(lla.to_vec()));
NeighbourAddRequest {
handle,
message,
replace: false,
}
}
pub fn state(mut self, state: u16) -> Self {
self.message.header.state = state;
self
}
pub fn flags(mut self, flags: u8) -> Self {
self.message.header.flags = flags;
self
}
pub fn ntype(mut self, ntype: u8) -> Self {
self.message.header.ntype = ntype;
self
}
pub fn link_local_address(mut self, addr: &[u8]) -> Self {
let lla = self.message.nlas.iter_mut().find_map(|nla| match nla {
Nla::LinkLocalAddress(lla) => Some(lla),
_ => None,
});
if let Some(lla) = lla {
*lla = addr.to_vec();
} else {
self.message.nlas.push(Nla::LinkLocalAddress(addr.to_vec()));
}
self
}
pub fn destination(mut self, addr: IpAddr) -> Self {
let dst = self.message.nlas.iter_mut().find_map(|nla| match nla {
Nla::Destination(dst) => Some(dst),
_ => None,
});
let addr = match addr {
IpAddr::V4(v4) => v4.octets().to_vec(),
IpAddr::V6(v6) => v6.octets().to_vec(),
};
if let Some(dst) = dst {
*dst = addr;
} else {
self.message.nlas.push(Nla::Destination(addr));
}
self
}
pub fn replace(self) -> Self {
Self {
replace: true,
..self
}
}
pub async fn execute(self) -> Result<(), Error> {
let NeighbourAddRequest {
mut handle,
message,
replace,
} = self;
let mut req = NetlinkMessage::from(RtnlMessage::NewNeighbour(message));
let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };
req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;
let mut response = handle.request(req)?;
while let Some(message) = response.next().await {
if let NetlinkPayload::Error(err) = message.payload {
return Err(Error::NetlinkError(err));
}
}
Ok(())
}
pub fn message_mut(&mut self) -> &mut NeighbourMessage {
&mut self.message
}
}