portforwarder_rs/
port_forwarder.rs1use igd::{self, AddAnyPortError, AddPortError, RemovePortError, SearchError, SearchOptions};
7use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4};
8
9pub use igd::PortMappingProtocol;
10
11#[derive(Debug)]
12pub struct Port {
13 pub proto: PortMappingProtocol,
14 pub num: u16,
15}
16
17impl PartialEq for Port {
18 fn eq(&self, other: &Port) -> bool {
19 self.proto == other.proto && self.num == other.num
20 }
21}
22
23#[derive(Debug)]
24pub struct Forwarder {
25 pub gateway: igd::Gateway,
26 pub network_interface: Ipv4Addr,
27 pub open_ports: Vec<Port>,
28}
29
30pub fn create_forwarder(interface_ip: Ipv4Addr) -> Result<Forwarder, SearchError> {
31 igd::search_gateway(SearchOptions {
32 bind_addr: SocketAddr::V4(SocketAddrV4::new(interface_ip, 0)),
33 ..Default::default()
34 })
35 .map(|gateway| Forwarder {
36 gateway,
37 network_interface: interface_ip,
38 open_ports: Vec::new(),
39 })
40}
41
42pub fn create_forwarder_from_any<I>(interface_ips: I) -> Result<Forwarder, Vec<SearchError>>
43where
44 I: IntoIterator<Item = Ipv4Addr>,
45{
46 let mut errors = Vec::new();
47 for interface_ip in interface_ips {
48 match create_forwarder(interface_ip) {
49 Ok(forwarder) => return Ok(forwarder),
50 Err(error) => errors.push(error),
51 }
52 }
53 Err(errors)
54}
55
56impl Forwarder {
57 pub fn forward_any_port(
58 &mut self,
59 local_port: u16,
60 proto: PortMappingProtocol,
61 name: &str,
62 ) -> Result<u16, AddAnyPortError> {
63 self.gateway
64 .add_any_port(
65 proto,
66 SocketAddrV4::new(self.network_interface, local_port),
67 0,
68 name,
69 )
70 .map(|port| {
71 self.open_ports.push(Port { proto, num: port });
72 port
73 })
74 }
75 pub fn forward_port(
76 &mut self,
77 local_port: u16,
78 remote_port: u16,
79 proto: PortMappingProtocol,
80 name: &str,
81 ) -> Result<(), AddPortError> {
82 self.gateway
83 .add_port(
84 proto,
85 remote_port,
86 SocketAddrV4::new(self.network_interface, local_port),
87 0,
88 name,
89 )
90 .map(|()| {
91 self.open_ports.push(Port {
92 proto,
93 num: remote_port,
94 });
95 })
96 }
97 pub fn remove_port(
98 &mut self,
99 remote_port: u16,
100 proto: PortMappingProtocol,
101 ) -> Result<(), RemovePortError> {
102 if let Some(pos) = self.open_ports.iter().position(|el| {
103 *el == Port {
104 proto,
105 num: remote_port,
106 }
107 }) {
108 self.open_ports.remove(pos);
109 } else {
110 println!(
111 "Remote port {} {} was not opened by this Forwarder! Removing anyway...",
112 proto, remote_port
113 );
114 }
115 self.gateway.remove_port(proto, remote_port)
116 }
117}
118
119impl Drop for Forwarder {
120 fn drop(&mut self) {
121 println!("Closing open ports...");
122 for port in &self.open_ports {
123 let num = port.num;
124 let proto = port.proto;
125 println!("Closing port {} {}...", proto, num);
126 if self.gateway.remove_port(proto, num).is_err() {
127 println!("Failed to close port {} {} on exit!", proto, num);
128 }
129 }
130 }
131}