1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
32
33use super::builder::MessageBuilder;
34use super::connection::Connection;
35use super::error::{Error, Result};
36use super::message::{NLM_F_ACK, NLM_F_REQUEST, NlMsgType};
37use super::protocol::Route;
38use super::types::neigh::{NdMsg, NdaAttr, NeighborState, ntf, nud};
39
40const NLM_F_CREATE: u16 = 0x400;
42const NLM_F_EXCL: u16 = 0x200;
44
45const AF_INET: u8 = 2;
47const AF_INET6: u8 = 10;
48
49pub use super::types::neigh::NeighborState as State;
51
52pub trait NeighborConfig {
54 fn interface(&self) -> &str;
56
57 fn build(&self) -> Result<MessageBuilder>;
59
60 fn build_delete(&self) -> Result<MessageBuilder>;
62}
63
64#[derive(Debug, Clone)]
84pub struct Neighbor {
85 interface: String,
86 destination: IpAddr,
88 lladdr: Option<Vec<u8>>,
90 state: u16,
92 flags: u8,
94 vlan: Option<u16>,
96 vni: Option<u32>,
98 master: Option<u32>,
100}
101
102impl Neighbor {
103 pub fn new_v4(interface: impl Into<String>, destination: Ipv4Addr) -> Self {
110 Self {
111 interface: interface.into(),
112 destination: IpAddr::V4(destination),
113 lladdr: None,
114 state: nud::PERMANENT,
115 flags: 0,
116 vlan: None,
117 vni: None,
118 master: None,
119 }
120 }
121
122 pub fn new_v6(interface: impl Into<String>, destination: Ipv6Addr) -> Self {
129 Self {
130 interface: interface.into(),
131 destination: IpAddr::V6(destination),
132 lladdr: None,
133 state: nud::PERMANENT,
134 flags: 0,
135 vlan: None,
136 vni: None,
137 master: None,
138 }
139 }
140
141 pub fn new(interface: impl Into<String>, destination: IpAddr) -> Self {
143 Self {
144 interface: interface.into(),
145 destination,
146 lladdr: None,
147 state: nud::PERMANENT,
148 flags: 0,
149 vlan: None,
150 vni: None,
151 master: None,
152 }
153 }
154
155 pub fn lladdr(mut self, addr: [u8; 6]) -> Self {
157 self.lladdr = Some(addr.to_vec());
158 self
159 }
160
161 pub fn lladdr_bytes(mut self, addr: impl Into<Vec<u8>>) -> Self {
163 self.lladdr = Some(addr.into());
164 self
165 }
166
167 pub fn state(mut self, state: NeighborState) -> Self {
169 self.state = state as u16;
170 self
171 }
172
173 pub fn permanent(mut self) -> Self {
175 self.state = nud::PERMANENT;
176 self
177 }
178
179 pub fn reachable(mut self) -> Self {
181 self.state = nud::REACHABLE;
182 self
183 }
184
185 pub fn stale(mut self) -> Self {
187 self.state = nud::STALE;
188 self
189 }
190
191 pub fn noarp(mut self) -> Self {
193 self.state = nud::NOARP;
194 self
195 }
196
197 pub fn proxy(mut self) -> Self {
199 self.flags |= ntf::PROXY;
200 self
201 }
202
203 pub fn router(mut self) -> Self {
205 self.flags |= ntf::ROUTER;
206 self
207 }
208
209 pub fn extern_learn(mut self) -> Self {
211 self.flags |= ntf::EXT_LEARNED;
212 self
213 }
214
215 pub fn vlan(mut self, vlan_id: u16) -> Self {
217 self.vlan = Some(vlan_id);
218 self
219 }
220
221 pub fn vni(mut self, vni: u32) -> Self {
223 self.vni = Some(vni);
224 self
225 }
226
227 pub fn master(mut self, master: impl Into<String>) -> Self {
229 if let Ok(idx) = ifname_to_index(&master.into()) {
230 self.master = Some(idx);
231 }
232 self
233 }
234}
235
236impl NeighborConfig for Neighbor {
237 fn interface(&self) -> &str {
238 &self.interface
239 }
240
241 fn build(&self) -> Result<MessageBuilder> {
242 let ifindex = ifname_to_index(&self.interface)?;
243
244 let family = match self.destination {
245 IpAddr::V4(_) => AF_INET,
246 IpAddr::V6(_) => AF_INET6,
247 };
248
249 let mut builder = MessageBuilder::new(
250 NlMsgType::RTM_NEWNEIGH,
251 NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL,
252 );
253
254 let mut ndmsg = NdMsg::new()
255 .with_family(family)
256 .with_ifindex(ifindex as i32);
257 ndmsg.ndm_state = self.state;
258 ndmsg.ndm_flags = self.flags;
259
260 builder.append(&ndmsg);
261
262 match self.destination {
264 IpAddr::V4(addr) => {
265 builder.append_attr(NdaAttr::Dst as u16, &addr.octets());
266 }
267 IpAddr::V6(addr) => {
268 builder.append_attr(NdaAttr::Dst as u16, &addr.octets());
269 }
270 }
271
272 if let Some(ref lladdr) = self.lladdr {
274 builder.append_attr(NdaAttr::Lladdr as u16, lladdr);
275 }
276
277 if let Some(vlan) = self.vlan {
279 builder.append_attr_u16(NdaAttr::Vlan as u16, vlan);
280 }
281
282 if let Some(vni) = self.vni {
284 builder.append_attr_u32(NdaAttr::Vni as u16, vni);
285 }
286
287 if let Some(master) = self.master {
289 builder.append_attr_u32(NdaAttr::Master as u16, master);
290 }
291
292 Ok(builder)
293 }
294
295 fn build_delete(&self) -> Result<MessageBuilder> {
296 let ifindex = ifname_to_index(&self.interface)?;
297
298 let family = match self.destination {
299 IpAddr::V4(_) => AF_INET,
300 IpAddr::V6(_) => AF_INET6,
301 };
302
303 let mut builder = MessageBuilder::new(NlMsgType::RTM_DELNEIGH, NLM_F_REQUEST | NLM_F_ACK);
304
305 let ndmsg = NdMsg::new()
306 .with_family(family)
307 .with_ifindex(ifindex as i32);
308
309 builder.append(&ndmsg);
310
311 match self.destination {
313 IpAddr::V4(addr) => {
314 builder.append_attr(NdaAttr::Dst as u16, &addr.octets());
315 }
316 IpAddr::V6(addr) => {
317 builder.append_attr(NdaAttr::Dst as u16, &addr.octets());
318 }
319 }
320
321 Ok(builder)
322 }
323}
324
325fn ifname_to_index(name: &str) -> Result<u32> {
331 let path = format!("/sys/class/net/{}/ifindex", name);
332 let content = std::fs::read_to_string(&path)
333 .map_err(|_| Error::InvalidMessage(format!("interface not found: {}", name)))?;
334 content
335 .trim()
336 .parse()
337 .map_err(|_| Error::InvalidMessage(format!("invalid ifindex for: {}", name)))
338}
339
340impl Connection<Route> {
345 pub async fn add_neighbor<N: NeighborConfig>(&self, config: N) -> Result<()> {
361 let builder = config.build()?;
362 self.send_ack(builder).await
363 }
364
365 pub async fn del_neighbor<N: NeighborConfig>(&self, config: N) -> Result<()> {
367 let builder = config.build_delete()?;
368 self.send_ack(builder).await
369 }
370
371 pub async fn del_neighbor_v4(&self, ifname: &str, destination: Ipv4Addr) -> Result<()> {
379 let neigh = Neighbor::new_v4(ifname, destination);
380 self.del_neighbor(neigh).await
381 }
382
383 pub async fn del_neighbor_v6(&self, ifname: &str, destination: Ipv6Addr) -> Result<()> {
385 let neigh = Neighbor::new_v6(ifname, destination);
386 self.del_neighbor(neigh).await
387 }
388
389 pub async fn replace_neighbor<N: NeighborConfig>(&self, config: N) -> Result<()> {
393 let builder = config.build()?;
395 self.send_ack(builder).await
396 }
397
398 pub async fn flush_neighbors(&self, ifname: &str) -> Result<()> {
406 let neighbors = self.get_neighbors_for(ifname).await?;
407
408 for neigh in neighbors {
409 if let Some(dest) = neigh.destination {
410 if neigh.state() == NeighborState::Permanent {
413 continue;
414 }
415
416 if let Err(e) = self.del_neighbor(Neighbor::new(ifname, dest)).await {
417 if !e.is_not_found() {
419 return Err(e);
420 }
421 }
422 }
423 }
424
425 Ok(())
426 }
427
428 pub async fn add_proxy_arp(&self, ifname: &str, destination: Ipv4Addr) -> Result<()> {
436 let neigh = Neighbor::new_v4(ifname, destination).proxy();
437 self.add_neighbor(neigh).await
438 }
439
440 pub async fn del_proxy_arp(&self, ifname: &str, destination: Ipv4Addr) -> Result<()> {
442 let neigh = Neighbor::new_v4(ifname, destination).proxy();
443 self.del_neighbor(neigh).await
444 }
445}