Skip to content

Commit d98f70d

Browse files
committed
refactor: replace socket2 with tokio::net::TcpSocket and enhance release notes generation
1 parent d1e97b8 commit d98f70d

4 files changed

Lines changed: 72 additions & 133 deletions

File tree

.github/workflows/release.yml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ jobs:
8080
needs: build
8181
runs-on: ubuntu-latest
8282
steps:
83+
- name: Checkout
84+
uses: actions/checkout@v4
85+
with:
86+
fetch-depth: 0
87+
8388
- name: Download all artifacts
8489
uses: actions/download-artifact@v4
8590
with:
@@ -99,8 +104,30 @@ jobs:
99104
done
100105
ls -la release/
101106
107+
- name: Generate release notes
108+
id: release_notes
109+
run: |
110+
# Get the previous tag
111+
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
112+
CURRENT_TAG=${GITHUB_REF#refs/tags/}
113+
114+
echo "## What's Changed" > release_notes.md
115+
echo "" >> release_notes.md
116+
117+
if [ -z "$PREV_TAG" ]; then
118+
# First release, get all commits
119+
git log --pretty=format:"- %s (%h)" >> release_notes.md
120+
else
121+
# Get commits between tags
122+
git log --pretty=format:"- %s (%h)" ${PREV_TAG}..${CURRENT_TAG} >> release_notes.md
123+
fi
124+
125+
echo "" >> release_notes.md
126+
echo "" >> release_notes.md
127+
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG:-$(git rev-list --max-parents=0 HEAD)}...${CURRENT_TAG}" >> release_notes.md
128+
102129
- name: Create Release
103130
uses: softprops/action-gh-release@v2
104131
with:
105132
files: release/*
106-
generate_release_notes: true
133+
body_path: release_notes.md

Cargo.lock

Lines changed: 10 additions & 94 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,3 @@ tracing = "0.1"
1212
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
1313
ipnet = "2"
1414
rand = "0.8"
15-
socket2 = "0.5"

src/main.rs

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
use clap::Parser;
22
use ipnet::IpNet;
33
use rand::Rng;
4-
use socket2::{Domain, Protocol, Socket, Type};
5-
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
4+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
65
use std::sync::Arc;
76
use thiserror::Error;
87
use tokio::io::{AsyncReadExt, AsyncWriteExt};
98
use tokio::net::{TcpListener, TcpSocket, TcpStream};
109
use tracing::{error, info, warn};
1110

12-
#[cfg(unix)]
13-
use std::os::unix::io::{FromRawFd, IntoRawFd};
14-
1511
// SOCKS5 protocol constants
1612
const SOCKS_VERSION: u8 = 0x05;
1713

@@ -342,39 +338,40 @@ async fn handle_request(stream: &mut TcpStream, config: &ServerConfig) -> Result
342338
let local_ip = random_ip_from_cidr(cidr);
343339
info!("Connecting to {} via {}", target, local_ip);
344340

345-
// Resolve target address (handles both IP and domain names)
346-
let mut addrs = tokio::net::lookup_host(&target).await?;
347-
let remote_addr = match local_ip {
348-
IpAddr::V4(_) => addrs.find(|a| a.is_ipv4()),
349-
IpAddr::V6(_) => addrs.find(|a| a.is_ipv6()),
350-
};
351-
352-
match remote_addr {
353-
Some(addr) => {
354-
let domain = match local_ip {
355-
IpAddr::V4(_) => Domain::IPV4,
356-
IpAddr::V6(_) => Domain::IPV6,
357-
};
358-
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
359-
360-
// Enable IP_FREEBIND to bind to addresses not yet configured on the interface
361-
#[cfg(target_os = "linux")]
362-
socket.set_freebind(true)?;
363-
364-
socket.bind(&SocketAddr::new(local_ip, 0).into())?;
365-
socket.set_nonblocking(true)?;
366-
367-
// Convert socket2::Socket to tokio::TcpSocket via raw fd
368-
#[cfg(unix)]
369-
let tcp_socket = unsafe { TcpSocket::from_raw_fd(socket.into_raw_fd()) };
370-
371-
tcp_socket.connect(addr).await
372-
}
373-
None => {
374-
// Fallback: try to connect without binding if no matching address family
375-
warn!("No matching address family for {}, connecting without bind", target);
376-
TcpStream::connect(&target).await
341+
// Resolve target address and try to connect
342+
match target.to_socket_addrs() {
343+
Ok(addrs) => {
344+
let mut last_err = None;
345+
let mut connected = None;
346+
347+
for addr in addrs {
348+
// Create socket matching the local IP family
349+
let socket = match local_ip {
350+
IpAddr::V4(_) if addr.is_ipv4() => TcpSocket::new_v4()?,
351+
IpAddr::V6(_) if addr.is_ipv6() => TcpSocket::new_v6()?,
352+
_ => continue, // Skip if address family doesn't match
353+
};
354+
355+
let bind_addr = SocketAddr::new(local_ip, 0);
356+
if socket.bind(bind_addr).is_ok() {
357+
match socket.connect(addr).await {
358+
Ok(stream) => {
359+
connected = Some(stream);
360+
break;
361+
}
362+
Err(e) => last_err = Some(e),
363+
}
364+
}
365+
}
366+
367+
match connected {
368+
Some(stream) => Ok(stream),
369+
None => Err(last_err.unwrap_or_else(|| {
370+
std::io::Error::new(std::io::ErrorKind::Other, "No matching address family")
371+
})),
372+
}
377373
}
374+
Err(e) => Err(e),
378375
}
379376
} else {
380377
info!("Connecting to {}", target);

0 commit comments

Comments
 (0)