Skip to content

Commit 7193c6e

Browse files
pseusyspseusys
andauthored
Transition to native netlink library bindings (#28)
* caerulean migrated to netlink * rtnetlink crate migration * linting errors fixed * tests fixed * tests fixed * lint fixed * rule changed --------- Co-authored-by: pseusys <aleksandr.sergeev.ad@gmail.com>
1 parent 1f8b5b9 commit 7193c6e

File tree

15 files changed

+285
-441
lines changed

15 files changed

+285
-441
lines changed

caerulean/whirlpool/protocol/port_server.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ func (p *PortServer) Read(buffer *betterbuf.Buffer, viridianDict *users.Viridian
5656
logrus.Debugf("Parsed packet header from viridian %d: type %d, data %d, tail %d", p.peerID, msgType, dataLength, tailLength)
5757

5858
var value *betterbuf.Buffer
59-
if msgType == TYPE_DATA {
59+
switch msgType {
60+
case TYPE_DATA:
6061
dataBuffer := buffer.Rebuffer(encryptedHeaderLength, encryptedHeaderLength+int(dataLength))
6162
s, err := io.ReadFull(p.socket, dataBuffer.Slice())
6263
if err != nil {
@@ -79,9 +80,9 @@ func (p *PortServer) Read(buffer *betterbuf.Buffer, viridianDict *users.Viridian
7980
}
8081
logrus.Debugf("Parsed packet data from viridian %d", p.peerID)
8182

82-
} else if msgType == TYPE_TERMINATION {
83+
case TYPE_TERMINATION:
8384
return nil, fmt.Errorf("connection with viridian %d terminated", p.peerID)
84-
} else {
85+
default:
8586
return nil, fmt.Errorf("unexpected message type received from viridian %d: %d", p.peerID, msgType)
8687
}
8788

caerulean/whirlpool/tunnel/interface.go

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ package tunnel
22

33
import (
44
"fmt"
5-
"strconv"
5+
"os"
66

77
"github.com/sirupsen/logrus"
8+
"github.com/vishvananda/netlink"
89
)
910

1011
// Create and open tunnel interface.
@@ -14,7 +15,7 @@ import (
1415
// Accept external IP address as a string.
1516
// Return nil if interface opened successfully, error otherwise.
1617
func (conf *TunnelConfig) openInterface(extIP string) error {
17-
// Cast sunnel name, ip and CIDR to string
18+
// Cast tunnel name, ip and CIDR to string
1819
tunnelName := conf.Tunnel.Name()
1920
tunnelString := conf.IP.String()
2021
tunnelCIDR, _ := conf.Network.Mask.Size()
@@ -27,28 +28,38 @@ func (conf *TunnelConfig) openInterface(extIP string) error {
2728
}
2829
conf.mtu = int32(tunnelInterface.MTU)
2930
}
30-
tunnelMTU := strconv.FormatInt(int64(conf.mtu), 10)
3131

32-
// Setup tunnel interface MTU
33-
_, err := runCommand("ip", "link", "set", "dev", tunnelName, "mtu", tunnelMTU)
32+
// Lookup tunnel link by name
33+
link, err := netlink.LinkByName(tunnelName)
3434
if err != nil {
35+
return fmt.Errorf("could not get link %s: %v", tunnelName, err)
36+
}
37+
38+
// Setup tunnel interface MTU
39+
if err := netlink.LinkSetMTU(link, int(conf.mtu)); err != nil {
3540
return fmt.Errorf("error setting tunnel MTU: %v", err)
3641
}
3742

38-
// Setup IP address for tunnel interface
39-
_, err = runCommand("ip", "addr", "add", fmt.Sprintf("%s/%d", tunnelString, tunnelCIDR), "dev", tunnelName)
43+
// Parse tunnel IP and CIDR
44+
addr, err := netlink.ParseAddr(fmt.Sprintf("%s/%d", tunnelString, tunnelCIDR))
4045
if err != nil {
41-
return fmt.Errorf("error setting tunnel IP address: %v", err)
46+
return fmt.Errorf("invalid tunnel address: %v", err)
4247
}
4348

44-
// Enable tunnel interfaces
45-
_, err = runCommand("ip", "link", "set", "dev", tunnelName, "up")
46-
if err != nil {
49+
// Setup IP address for tunnel interface
50+
if err := netlink.AddrAdd(link, addr); err != nil {
51+
if !os.IsExist(err) {
52+
return fmt.Errorf("error adding tunnel address: %v", err)
53+
}
54+
}
55+
56+
// Enable tunnel interface
57+
if err := netlink.LinkSetUp(link); err != nil {
4758
return fmt.Errorf("error setting tunnel UP: %v", err)
4859
}
4960

5061
// Log and return no error
51-
logrus.Infof("Interface %s opened (IP: %s, MTU: %s)", tunnelName, tunnelString, tunnelMTU)
62+
logrus.Infof("Interface %s opened (IP: %s, MTU: %d)", tunnelName, tunnelString, conf.mtu)
5263
return nil
5364
}
5465

@@ -59,14 +70,18 @@ func (conf *TunnelConfig) closeInterface() error {
5970
// Receive tunnel name
6071
tunnelName := conf.Tunnel.Name()
6172

62-
// Disable and remove tunnel
63-
_, err := runCommand("ip", "link", "set", "dev", tunnelName, "down")
73+
// Lookup tunnel link by name
74+
link, err := netlink.LinkByName(tunnelName)
6475
if err != nil {
76+
return fmt.Errorf("could not get link %s: %v", tunnelName, err)
77+
}
78+
79+
// Disable and remove tunnel
80+
if err := netlink.LinkSetDown(link); err != nil {
6581
return fmt.Errorf("error shutting down tunnel interface: %v", err)
6682
}
6783

68-
_, err = runCommand("ip", "link", "del", "dev", tunnelName)
69-
if err != nil {
84+
if err := netlink.LinkDel(link); err != nil {
7085
return fmt.Errorf("error deleting tunnel interface: %v", err)
7186
}
7287

caerulean/whirlpool/tunnel/utils.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"fmt"
77
"net"
8-
"os/exec"
98
"strings"
109

1110
"github.com/sirupsen/logrus"
@@ -14,20 +13,6 @@ import (
1413

1514
var DEFAULT_IP_ADDRESS = []byte{0, 0, 0, 0}
1615

17-
// Execute console command.
18-
// Accept executable name and vararg command arguments.
19-
// Return stdout and stderr as a string, terminate if command execution failed.
20-
func runCommand(cmd string, args ...string) (string, error) {
21-
command := exec.Command(cmd, args...)
22-
output, err := command.CombinedOutput()
23-
if err != nil {
24-
logrus.Errorf("Command %s output: %s", cmd, output)
25-
return "", fmt.Errorf("error running command: %v", args)
26-
} else {
27-
return string(output), nil
28-
}
29-
}
30-
3116
func findDefaultInterface() (*net.IPNet, error) {
3217
routes, err := netlink.RouteList(nil, netlink.FAMILY_ALL)
3318
if err != nil {

viridian/reef/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ x25519-dalek = { version = "^2.0.1", features = ["static_secrets"] }
3434

3535
[target.'cfg(target_os = "linux")'.dependencies]
3636
nftables = "^0.6.3"
37-
neli = "^0.6.4"
37+
rtnetlink = "^0.17.0"
3838
tun = { version = "^0.7.1", features = ["async"] }
3939

4040
[target.'cfg(target_os = "windows")'.dependencies]

viridian/reef/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ iptables -t mangle -I INPUT 1 -i <INPUT_INTERFACE> -j ACCEPT
103103
iptables -t mangle -I INPUT 1 -i <INPUT_INTERFACE> -j MARK --set-mark <SVR_CODE>
104104
```
105105

106+
And don't forget enabling IPv4 packet forwarding by running: `echo 1 > /proc/sys/net/ipv4/ip_forward`.
107+
106108
### Windows
107109

108110
> Depends on: `WinDivert`, `WMI`, `IP Helper`

viridian/reef/src/lib/mod.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,12 @@ pub mod crypto;
88
pub mod general;
99
pub mod link;
1010
pub mod protocol;
11+
pub mod rng;
1112
pub mod runtime;
1213
pub mod tunnel;
1314
pub mod utils;
1415
pub mod viridian;
1516

16-
#[cfg(test)]
17-
#[path = "../../tests/rng.rs"]
18-
pub mod rng;
19-
20-
#[cfg(not(test))]
21-
pub mod rng;
22-
2317
pub type DynResult<T> = Result<T, Box<dyn Error + Sync + Send>>;
2418

2519
pub trait Reader: Send + 'static {

viridian/reef/src/lib/rng.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,39 @@
1-
use rand::rngs::OsRng;
21
use rand::CryptoRng;
32
use rand::Rng;
43

4+
#[cfg(test)]
5+
struct MockRng;
6+
7+
#[cfg(test)]
8+
impl rand::RngCore for MockRng {
9+
fn next_u32(&mut self) -> u32 {
10+
0u32
11+
}
12+
13+
fn next_u64(&mut self) -> u64 {
14+
0u64
15+
}
16+
17+
fn fill_bytes(&mut self, dest: &mut [u8]) {
18+
dest.fill(0u8)
19+
}
20+
21+
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> {
22+
Ok(dest.fill(0u8))
23+
}
24+
}
25+
26+
#[cfg(test)]
27+
impl CryptoRng for MockRng {}
28+
29+
#[inline]
30+
#[cfg(test)]
31+
pub(crate) fn get_rng() -> impl Rng + CryptoRng {
32+
MockRng
33+
}
34+
535
#[inline]
36+
#[cfg(not(test))]
637
pub(crate) fn get_rng() -> impl Rng + CryptoRng {
7-
OsRng
38+
rand::rngs::OsRng
839
}

viridian/reef/src/lib/runtime.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ lazy_static! {
55
pub static ref LocalTokioRuntime: Runtime = Builder::new_multi_thread().enable_all().build().expect("Failed to start TYPHOON runtime!");
66
}
77

8+
#[macro_export]
9+
macro_rules! run_coroutine_async {
10+
($future:expr) => {{
11+
match tokio::runtime::Handle::try_current() {
12+
Ok(res) => res.spawn($future),
13+
Err(_) => $crate::runtime::LocalTokioRuntime.spawn($future),
14+
}
15+
}};
16+
}
17+
818
#[macro_export]
919
macro_rules! run_coroutine_sync {
1020
($future:expr) => {{

0 commit comments

Comments
 (0)