Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
T
tun
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Railgun
tun
Commits
d70d4b10
Commit
d70d4b10
authored
Feb 02, 2025
by
nanamicat
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
docker
parent
474d54a0
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
136 additions
and
100 deletions
+136
-100
Dockerfile
Dockerfile
+12
-0
src/main.rs
src/main.rs
+124
-100
No files found.
Dockerfile
0 → 100644
View file @
d70d4b10
FROM
rust:alpine as builder
WORKDIR
/usr/src/app
COPY
. .
RUN
cargo
install
--path
.
FROM
alpine
RUN
apk
--no-cache
add libgcc libstdc++ bash iproute2 iptables ipset netcat-openbsd
COPY
--from=builder /usr/local/cargo/bin/tun1 /usr/local/bin/tun
COPY
./entrypoint.sh /entrypoint.sh
ENTRYPOINT
["/entrypoint.sh"]
CMD
["tun"]
src/main.rs
View file @
d70d4b10
use
pnet
::
packet
::
ipv4
::
Ipv4Packet
;
use
pnet
::
packet
::
Packet
;
use
socket2
::{
Domain
,
Protocol
,
SockAddr
,
Socket
,
Type
};
use
socket2
::{
Domain
,
Protocol
,
Socket
,
Type
};
use
std
::
error
::
Error
;
use
std
::
io
::{
BufRead
,
Read
,
Write
};
use
std
::
mem
::{
transmute
,
MaybeUninit
};
use
std
::
sync
::{
Arc
,
Mutex
};
use
std
::
io
::{
Read
,
Write
};
use
std
::
mem
::{
size_of
,
MaybeUninit
};
use
std
::
net
::
ToSocketAddrs
;
use
std
::
process
::
Command
;
use
std
::
sync
::{
Arc
,
RwLock
};
use
std
::{
env
,
thread
};
use
std
::
net
::{
SocketAddr
,
SocketAddrV4
};
use
std
::
net
::
UdpSocket
;
#[repr(C)]
pub
struct
Meta
{
...
...
@@ -23,17 +20,16 @@ struct Secret {
}
impl
Secret
{
fn
new
(
key
:
&
String
)
->
Secret
{
Se
cret
{
fn
new
(
key
:
&
str
)
->
Self
{
Se
lf
{
key
:
key
.as_bytes
()
.to_vec
(),
}
}
fn
encrypt
(
&
self
,
data
:
&
mut
[
u8
])
{
for
(
i
,
b
yte
)
in
data
.iter_mut
()
.enumerate
()
{
*
b
yte
^=
self
.key
[
i
%
self
.key
.len
()];
for
(
i
,
b
)
in
data
.iter_mut
()
.enumerate
()
{
*
b
^=
self
.key
[
i
%
self
.key
.len
()];
}
}
fn
decrypt
(
&
self
,
data
:
&
mut
[
u8
])
{
self
.encrypt
(
data
);
}
...
...
@@ -44,108 +40,136 @@ fn main() -> Result<(), Box<dyn Error>> {
let
remote_id
:
u8
=
env
::
var
(
"REMOTE_ID"
)
?
.parse
()
?
;
let
local_secret
=
Secret
::
new
(
&
env
::
var
(
"LOCAL_SECRET"
)
?
);
let
remote_secret
=
Secret
::
new
(
&
env
::
var
(
"REMOTE_SECRET"
)
?
);
let
remote_addr
:
Arc
<
Mutex
<
Option
<
SockAddr
>>>
=
Arc
::
new
(
Mutex
::
new
(
match
env
::
var
(
"REMOTE_ADDR"
)
{
let
proto
:
i32
=
env
::
var
(
"PROTO"
)
?
.parse
()
?
;
let
up
=
env
::
var
(
"UP_SCRIPT"
)
?
;
let
dev
=
env
::
var
(
"DEV"
)
?
;
let
family
=
if
env
::
var
(
"FAMILY"
)
?
.parse
::
<
u8
>
()
?
==
6
{
Domain
::
IPV6
}
else
{
Domain
::
IPV4
};
let
endpoint
=
Arc
::
new
(
RwLock
::
new
(
match
env
::
var
(
"ENDPOINT"
)
{
Ok
(
addr_str
)
=>
{
let
parsed
=
addr_str
.parse
::
<
SocketAddr
>
()
?
;
let
parsed
=
addr_str
.to_socket_addrs
()
?
.next
()
.unwrap
()
;
Some
(
parsed
.into
())
}
Err
(
_
)
=>
None
,
}
));
}));
let
mut
config
=
tun
::
Configuration
::
default
();
config
.address
((
10
,
0
,
0
,
local_id
))
.netmask
((
255
,
255
,
255
,
0
))
.destination
((
10
,
0
,
0
,
remote_id
))
.up
();
#[cfg(target_os
=
"linux"
)]
config
.platform_config
(|
config
|
{
config
.ensure_root_privileges
(
true
);
});
config
.tun_name
(
dev
)
.up
();
let
dev
=
tun
::
create
(
&
config
)
?
;
let
(
mut
reader
,
mut
writer
)
=
dev
.split
();
// 创建用于接收的原始套接字,协议号为 144
let
socket
=
Socket
::
new
(
Domain
::
IPV4
,
Type
::
RAW
,
Some
(
Protocol
::
from
(
144
)))
?
;
let
socket_arc
=
Arc
::
new
(
Mutex
::
new
(
socket
));
let
socket_for_inbound
=
Arc
::
clone
(
&
socket_arc
);
// Create a raw socket with protocol number 144
let
socket
=
Socket
::
new
(
family
,
Type
::
RAW
,
Some
(
Protocol
::
from
(
proto
)))
?
;
#[cfg(target_os
=
"linux"
)]
socket
.set_mark
(
env
::
var
(
"MARK"
)
?
.parse
()
?
);
let
socket_clone
=
socket
.try_clone
()
?
;
let
remote_addr_clone
=
Arc
::
clone
(
&
remote_addr
);
match
Command
::
new
(
up
)
.status
()
{
Ok
(
status
)
=>
{
if
!
status
.success
()
{
eprintln!
(
"Script exited with non-zero status: {}"
,
status
);
}
}
Err
(
e
)
=>
eprintln!
(
"Failed to run script '{}'"
,
e
),
}
let
inbound
=
thread
::
spawn
(
move
||
{
// Thread for receiving from WAN (raw socket) and writing to TUN
let
inbound
=
{
let
remote_addr
=
Arc
::
clone
(
&
endpoint
);
let
local_secret
=
local_secret
;
thread
::
spawn
(
move
||
{
let
mut
recv_buf
=
[
MaybeUninit
::
uninit
();
1500
];
loop
{
let
sock_guard
=
socket_for_inbound
.lock
()
.unwrap
();
match
sock_guard
.recv_from
(
&
mut
recv_buf
)
{
Ok
((
len
,
addr1
))
=>
{
println!
(
"recv from {:?}"
,
recv_buf
);
let
recv_buf2
:
&
mut
[
u8
]
=
unsafe
{
transmute
(
&
mut
recv_buf
[
..
len
])
};
if
let
Some
(
packet
)
=
Ipv4Packet
::
new
(
recv_buf2
)
{
let
header_length
=
packet
.get_header_length
()
as
usize
*
4
;
let
(
header
,
data
)
=
recv_buf2
.split_at_mut
(
header_length
);
let
(
meta1
,
payload
)
=
data
.split_at_mut
(
size_of
::
<
Meta
>
());
let
meta
:
&
Meta
=
unsafe
{
transmute
(
&
meta1
)
};
if
meta
.src_id
==
remote_id
&&
meta
.dst_id
==
local_id
&&
meta
.reversed
==
0
match
socket
.recv_from
(
&
mut
recv_buf
)
{
Ok
((
len
,
addr
))
=>
{
// Safely interpret the uninit buffer up to `len` as bytes
let
data
=
unsafe
{
std
::
slice
::
from_raw_parts_mut
(
recv_buf
.as_mut_ptr
()
as
*
mut
u8
,
len
)
};
if
let
Some
(
packet
)
=
Ipv4Packet
::
new
(
data
)
{
let
header_len
=
packet
.get_header_length
()
as
usize
*
4
;
let
(
_
ip_header
,
rest
)
=
data
.split_at_mut
(
header_len
);
if
rest
.len
()
<
size_of
::
<
Meta
>
()
{
// Malformed packet
continue
;
}
let
(
meta_bytes
,
payload
)
=
rest
.split_at_mut
(
size_of
::
<
Meta
>
());
// Extract meta
let
meta
=
Meta
{
src_id
:
meta_bytes
[
0
],
dst_id
:
meta_bytes
[
1
],
reversed
:
u16
::
from_le_bytes
([
meta_bytes
[
2
],
meta_bytes
[
3
]]),
};
// Check if it matches our expected IDs
if
meta
.src_id
==
remote_id
&&
meta
.dst_id
==
local_id
&&
meta
.reversed
==
0
{
let
mut
addr_lock
=
remote_addr_clone
.lock
()
.unwrap
();
*
addr_lock
=
Some
(
addr1
);
// Update remote address for outbound
*
remote_addr
.write
()
.unwrap
()
=
Some
(
addr
);
// Decrypt and push into TUN
local_secret
.decrypt
(
payload
);
writer
.write
(
payload
);
}
let
_
=
writer
.write_all
(
payload
);
}
else
{
// eprintln!("Dropping unexpected packet");
}
}
Err
(
e
)
=>
{
eprintln!
(
"接收数据包时出错: {:?}"
,
e
);
}
Err
(
e
)
=>
eprintln!
(
"Error receiving: {}"
,
e
),
}
}
});
})
};
let
outbound
=
thread
::
spawn
(
move
||
{
let
mut
recv_buf
=
[
0u8
;
1500
-
20
];
// Thread for reading from TUN, encrypting, and sending to WAN
let
outbound
=
{
let
remote_addr
=
Arc
::
clone
(
&
endpoint
);
let
remote_secret
=
remote_secret
;
thread
::
spawn
(
move
||
{
let
mut
buffer
=
[
0u8
;
1500
-
20
];
// minus typical IP header space
let
meta_size
=
size_of
::
<
Meta
>
();
// Pre-initialize with our Meta header (local -> remote)
let
meta
=
Meta
{
src_id
:
local_id
,
dst_id
:
remote_id
,
reversed
:
0
,
};
let
meta_size
=
size_of
::
<
Meta
>
();
unsafe
{
// Turn the Meta struct into bytes
let
meta_bytes
=
std
::
slice
::
from_raw_parts
(
&
meta
as
*
const
Meta
as
*
const
u8
,
meta_size
)
;
recv_buf
[
..
meta_size
]
.copy_from_slice
(
meta_bytes
);
}
unsafe
{
std
::
slice
::
from_raw_parts
(
&
meta
as
*
const
Meta
as
*
const
u8
,
meta_size
)
}
;
buffer
[
..
meta_size
]
.copy_from_slice
(
meta_bytes
);
loop
{
match
reader
.read
(
&
mut
recv_buf
[
meta_size
..
])
{
Ok
(
len
)
=>
{
println!
(
"recv from {:?}"
,
&
recv_buf
[
meta_size
..
meta_size
+
len
]);
let
maybe_remote
=
remote_addr
.lock
()
.unwrap
()
.clone
();
println!
(
"1"
);
if
let
Some
(
ref
remote
)
=
maybe_remote
{
println!
(
"2"
);
let
sock_guard
=
socket_arc
.lock
()
.unwrap
();
println!
(
"3"
);
remote_secret
.encrypt
(
&
mut
recv_buf
[
meta_size
..
meta_size
+
len
]);
println!
(
"4"
);
if
let
Err
(
e
)
=
sock_guard
.send_to
(
&
recv_buf
[
..
meta_size
+
len
],
remote
)
{
println!
(
"5"
);
eprintln!
(
"Error sending packet: {:?}"
,
e
);
match
reader
.read
(
&
mut
buffer
[
meta_size
..
])
{
Ok
(
n
)
if
n
>
0
=>
{
// If we have a known remote address, encrypt and send
if
let
Some
(
ref
addr
)
=
*
remote_addr
.read
()
.unwrap
()
{
remote_secret
.encrypt
(
&
mut
buffer
[
meta_size
..
meta_size
+
n
]);
if
let
Err
(
e
)
=
socket_clone
.send_to
(
&
buffer
[
..
meta_size
+
n
],
addr
)
{
eprintln!
(
"Error sending packet: {}"
,
e
);
}
}
else
{
eprintln!
(
"No remote address available; packet discard
ed."
);
eprintln!
(
"No remote address set; packet dropp
ed."
);
}
}
Err
(
_
)
=>
{}
Err
(
e
)
=>
eprintln!
(
"Error reading from TUN: {}"
,
e
),
_
=>
{}
}
}
});
inbound
.join
();
outbound
.join
();
})
};
let
_
=
inbound
.join
();
let
_
=
outbound
.join
();
Ok
(())
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment