Created
April 24, 2025 06:59
-
-
Save bojieli/7645122193ce95cdcce502479dca7aa2 to your computer and use it in GitHub Desktop.
Script to disable TCP congestion control and Nagle's algorithm for a specific IP address or domain
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Script to disable TCP congestion control and Nagle's algorithm for a specific IP address or domain | |
# Automatically installs dependencies and compiles a kernel module if needed | |
# Check if script is run as root | |
if [ "$(id -u)" -ne 0 ]; then | |
echo "This script must be run as root" >&2 | |
exit 1 | |
fi | |
# Function to install dependencies | |
install_dependencies() { | |
echo "Installing dependencies..." | |
if command -v apt-get &> /dev/null; then | |
apt-get update | |
apt-get install -y build-essential linux-headers-$(uname -r) iptables dnsutils | |
elif command -v yum &> /dev/null; then | |
yum install -y kernel-devel gcc make iptables bind-utils | |
elif command -v dnf &> /dev/null; then | |
dnf install -y kernel-devel gcc make iptables bind-utils | |
elif command -v pacman &> /dev/null; then | |
pacman -Sy --noconfirm base-devel linux-headers iptables bind-tools | |
else | |
echo "Unsupported package manager. Please install build-essential, linux headers, and iptables manually." | |
exit 1 | |
fi | |
} | |
# Function to resolve domain to IP | |
resolve_domain() { | |
local domain="$1" | |
local resolved_ip | |
echo "Resolving domain $domain to IP address..." | |
if command -v dig &> /dev/null; then | |
resolved_ip=$(dig +short "$domain" | grep -v "\.$" | head -n 1) | |
elif command -v host &> /dev/null; then | |
resolved_ip=$(host "$domain" | grep "has address" | head -n 1 | awk '{print $NF}') | |
elif command -v nslookup &> /dev/null; then | |
resolved_ip=$(nslookup "$domain" | grep -A2 "Name:" | grep "Address:" | head -n 1 | awk '{print $2}') | |
else | |
echo "No DNS resolution tools found. Please install dig, host, or nslookup." | |
exit 1 | |
fi | |
if [ -z "$resolved_ip" ]; then | |
echo "Failed to resolve domain $domain to IP address." | |
exit 1 | |
fi | |
echo "Domain $domain resolved to IP: $resolved_ip" | |
echo "$resolved_ip" | |
} | |
# Function to update the tcp_none module when it's in use | |
update_tcp_none_module() { | |
echo "Updating tcp_none module with unlimited cwnd..." | |
# Check if module is currently loaded | |
if lsmod | grep -q "tcp_none"; then | |
# Identify connections using the 'none' congestion control | |
active_connections=$(ss -ti | grep none) | |
if [ -n "$active_connections" ]; then | |
echo "Active connections found using tcp_none module:" | |
echo "$active_connections" | |
echo "These connections will be terminated to update the module." | |
read -p "Press Enter to continue or Ctrl+C to abort..." </dev/tty | |
# More aggressive connection termination approach | |
# 1. First try to kill processes | |
echo "Finding and terminating processes with active connections to $TARGET_IP..." | |
TARGET_CONNS=$(ss -tnp | grep "$TARGET_IP") | |
if [ -n "$TARGET_CONNS" ]; then | |
# Extract PIDs of processes using these connections | |
PIDS=$(echo "$TARGET_CONNS" | grep -oP 'pid=\K\d+' | sort -u) | |
if [ -n "$PIDS" ]; then | |
for PID in $PIDS; do | |
echo "Terminating process $PID" | |
kill -9 $PID 2>/dev/null || echo "Could not kill process $PID" | |
done | |
fi | |
fi | |
# 2. Create firewall rules to reset all connections to/from the target IP | |
echo "Adding firewall rules to reset connections to $TARGET_IP..." | |
iptables -F | |
iptables -A INPUT -p tcp -s $TARGET_IP -j REJECT --reject-with tcp-reset | |
iptables -A OUTPUT -p tcp -d $TARGET_IP -j REJECT --reject-with tcp-reset | |
# 3. Enable aggressive TCP TIME_WAIT connection handling | |
echo "Enabling aggressive TCP connection cleanup..." | |
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 2>/dev/null || true | |
echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse 2>/dev/null || true | |
echo 1 > /proc/sys/net/ipv4/tcp_abort_on_overflow 2>/dev/null || true | |
echo 10 > /proc/sys/net/ipv4/tcp_fin_timeout 2>/dev/null || true | |
# 4. Handle specific connections directly using ss output | |
echo "Directly targeting connections using 'none' congestion control..." | |
ss -tn state established | grep "$TARGET_IP" | awk '{print $4}' | while read local_addr; do | |
if [[ "$local_addr" == *:* ]]; then | |
local_ip=$(echo $local_addr | cut -d: -f1) | |
local_port=$(echo $local_addr | cut -d: -f2) | |
echo "Closing connection on local port $local_port" | |
iptables -A INPUT -p tcp --dport $local_port -j REJECT --reject-with tcp-reset | |
iptables -A OUTPUT -p tcp --sport $local_port -j REJECT --reject-with tcp-reset | |
fi | |
done | |
# 5. Wait and check again | |
echo "Waiting for connections to terminate..." | |
sleep 5 | |
# 6. Clean up the temporary iptables rules | |
iptables -F | |
fi | |
# Try to unload the module | |
echo "Attempting to unload tcp_none module..." | |
rmmod tcp_none 2>/dev/null | |
# If module is still loaded, try more aggressive approach | |
if lsmod | grep -q "tcp_none"; then | |
echo "Module still in use. Trying system-wide connection reset..." | |
# System-wide approach (DANGEROUS but effective) | |
echo "WARNING: This will reset ALL TCP connections on the system!" | |
read -p "Continue? [y/N] " confirm </dev/tty | |
if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then | |
# Reset all connections by toggling the network interface | |
DEFAULT_INTERFACE=$(ip route | grep default | head -n 1 | awk '{print $5}') | |
if [ -n "$DEFAULT_INTERFACE" ]; then | |
echo "Temporarily disabling interface $DEFAULT_INTERFACE..." | |
ip link set $DEFAULT_INTERFACE down | |
sleep 2 | |
ip link set $DEFAULT_INTERFACE up | |
sleep 2 | |
fi | |
# Try to unload again | |
rmmod tcp_none 2>/dev/null | |
fi | |
# Final check if module is unloaded | |
if lsmod | grep -q "tcp_none"; then | |
echo "Could not unload module. You may need to reboot the system." | |
echo "Continuing anyway to try compiling the new module..." | |
else | |
echo "Successfully unloaded tcp_none module." | |
fi | |
else | |
echo "Successfully unloaded tcp_none module." | |
fi | |
fi | |
# Navigate to module directory or create a new one | |
MODULE_DIR=$(mktemp -d) | |
cd "$MODULE_DIR" | |
# Create updated Makefile and module source | |
echo "Creating updated tcp_none module with unlimited cwnd..." | |
# Create Makefile (same as before) | |
cat > Makefile << 'EOF' | |
obj-m += tcp_none.o | |
all: | |
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules | |
clean: | |
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean | |
EOF | |
# Create updated tcp_none.c with unlimited cwnd | |
cat > tcp_none.c << 'EOF' | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/init.h> | |
#include <net/tcp.h> | |
static struct tcp_congestion_ops tcp_none; | |
static void tcp_none_init(struct sock *sk) | |
{ | |
/* Set congestion window to maximum possible value */ | |
struct tcp_sock *tp = tcp_sk(sk); | |
tp->snd_cwnd = UINT_MAX / 2; /* Use a very large value (near max of u32) */ | |
tp->snd_cwnd_clamp = UINT_MAX / 2; /* Also set the clamp to a very high value */ | |
} | |
static void tcp_none_cong_avoid(struct sock *sk, u32 ack, u32 acked) | |
{ | |
/* Always keep the congestion window maximized */ | |
struct tcp_sock *tp = tcp_sk(sk); | |
/* If cwnd somehow gets reduced, set it back to maximum */ | |
if (tp->snd_cwnd < UINT_MAX / 2) { | |
tp->snd_cwnd = UINT_MAX / 2; | |
} | |
} | |
static u32 tcp_none_ssthresh(struct sock *sk) | |
{ | |
/* Return maximum value */ | |
return TCP_INFINITE_SSTHRESH; | |
} | |
static u32 tcp_none_undo_cwnd(struct sock *sk) | |
{ | |
/* Return maximum value instead of current CWND */ | |
return UINT_MAX / 2; | |
} | |
static void tcp_none_cwnd_event(struct sock *sk, enum tcp_ca_event event) | |
{ | |
/* Force cwnd to stay at maximum regardless of events */ | |
struct tcp_sock *tp = tcp_sk(sk); | |
tp->snd_cwnd = UINT_MAX / 2; | |
} | |
static void tcp_none_pkts_acked(struct sock *sk, const struct ack_sample *sample) | |
{ | |
/* Do nothing */ | |
} | |
static struct tcp_congestion_ops tcp_none = { | |
.init = tcp_none_init, | |
.ssthresh = tcp_none_ssthresh, | |
.cong_avoid = tcp_none_cong_avoid, | |
.undo_cwnd = tcp_none_undo_cwnd, | |
.cwnd_event = tcp_none_cwnd_event, | |
.pkts_acked = tcp_none_pkts_acked, | |
.owner = THIS_MODULE, | |
.name = "none", | |
}; | |
static int __init tcp_none_register(void) | |
{ | |
printk(KERN_INFO "TCP None Congestion Control loaded with unlimited cwnd\n"); | |
return tcp_register_congestion_control(&tcp_none); | |
} | |
static void __exit tcp_none_unregister(void) | |
{ | |
printk(KERN_INFO "TCP None Congestion Control unloaded\n"); | |
tcp_unregister_congestion_control(&tcp_none); | |
} | |
module_init(tcp_none_register); | |
module_exit(tcp_none_unregister); | |
MODULE_AUTHOR("Kernel Module Generator"); | |
MODULE_LICENSE("GPL"); | |
MODULE_DESCRIPTION("TCP Congestion Control with No Algorithm and Unlimited CWND"); | |
EOF | |
# Compile the module | |
echo "Compiling updated kernel module..." | |
make | |
# Load the new module | |
echo "Loading updated kernel module..." | |
insmod tcp_none.ko | |
# Verify module loaded | |
if ! grep -q "none" /proc/sys/net/ipv4/tcp_available_congestion_control; then | |
echo "Failed to load 'none' congestion control module." | |
exit 1 | |
fi | |
echo "Successfully updated and loaded 'none' congestion control module with unlimited cwnd." | |
# Update routes to use the new module | |
echo "Updating routes to use new module..." | |
# Check if congctl is supported by ip route | |
if ip route help 2>&1 | grep -q "congctl"; then | |
ip route change default via "$DEFAULT_GATEWAY" dev "$DEFAULT_INTERFACE" table nocongestion congctl none | |
else | |
# Fallback if congctl is not supported | |
echo "congctl option not supported on this system" | |
ip route change default via "$DEFAULT_GATEWAY" dev "$DEFAULT_INTERFACE" table nocongestion | |
# Try using sysctl to set congestion control for specific interfaces | |
echo "Using alternative method to set congestion control" | |
echo "none" > /proc/sys/net/ipv4/tcp_congestion_control | |
fi | |
cd - >/dev/null | |
} | |
# Check if arguments include an update flag | |
if [ "$1" == "--update-module" ]; then | |
# Check if TARGET_IP was previously set | |
if [ -f /var/lib/no-congestion-target ]; then | |
TARGET_IP=$(cat /var/lib/no-congestion-target) | |
echo "Updating module for existing target: $TARGET_IP" | |
# Get default route interface and gateway | |
DEFAULT_ROUTE=$(ip route | grep default | head -n 1) | |
DEFAULT_INTERFACE=$(echo "$DEFAULT_ROUTE" | awk '{print $5}') | |
DEFAULT_GATEWAY=$(echo "$DEFAULT_ROUTE" | awk '{print $3}') | |
update_tcp_none_module | |
exit 0 | |
else | |
echo "No target IP found. Please run the script with a target IP first." | |
exit 1 | |
fi | |
fi | |
# Check arguments | |
if [ $# -ne 1 ]; then | |
echo "Usage: $0 <target_ip_or_domain>" | |
echo " or: $0 --update-module" | |
exit 1 | |
fi | |
# Check if input is an IP address or domain | |
if [[ "$1" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
# Input is an IP address | |
TARGET_IP="$1" | |
echo "Using IP address: $TARGET_IP" | |
else | |
# Input is likely a domain name | |
DOMAIN="$1" | |
# Resolve domain to IP | |
TARGET_IP=$(resolve_domain "$DOMAIN") | |
echo "Using domain $DOMAIN with resolved IP: $TARGET_IP" | |
fi | |
echo "Setting up no congestion control for connections to $TARGET_IP" | |
# Install dependencies | |
install_dependencies | |
# Check if 'none' congestion control is available | |
if ! grep -q "none" /proc/sys/net/ipv4/tcp_available_congestion_control; then | |
echo "'none' congestion control is not available. Creating kernel module..." | |
# Create temporary directory for kernel module | |
MODULE_DIR=$(mktemp -d) | |
cd "$MODULE_DIR" | |
# Create Makefile | |
cat > Makefile << 'EOF' | |
obj-m += tcp_none.o | |
all: | |
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules | |
clean: | |
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean | |
EOF | |
# Create kernel module source | |
cat > tcp_none.c << 'EOF' | |
#include <linux/module.h> | |
#include <linux/kernel.h> | |
#include <linux/init.h> | |
#include <net/tcp.h> | |
static struct tcp_congestion_ops tcp_none; | |
static void tcp_none_init(struct sock *sk) | |
{ | |
/* Set congestion window to maximum possible value */ | |
struct tcp_sock *tp = tcp_sk(sk); | |
tp->snd_cwnd = UINT_MAX / 2; /* Use a very large value (near max of u32) */ | |
tp->snd_cwnd_clamp = UINT_MAX / 2; /* Also set the clamp to a very high value */ | |
} | |
static void tcp_none_cong_avoid(struct sock *sk, u32 ack, u32 acked) | |
{ | |
/* Always keep the congestion window maximized */ | |
struct tcp_sock *tp = tcp_sk(sk); | |
/* If cwnd somehow gets reduced, set it back to maximum */ | |
if (tp->snd_cwnd < UINT_MAX / 2) { | |
tp->snd_cwnd = UINT_MAX / 2; | |
} | |
} | |
static u32 tcp_none_ssthresh(struct sock *sk) | |
{ | |
/* Return maximum value */ | |
return TCP_INFINITE_SSTHRESH; | |
} | |
static u32 tcp_none_undo_cwnd(struct sock *sk) | |
{ | |
/* Return maximum value instead of current CWND */ | |
return UINT_MAX / 2; | |
} | |
static void tcp_none_cwnd_event(struct sock *sk, enum tcp_ca_event event) | |
{ | |
/* Force cwnd to stay at maximum regardless of events */ | |
struct tcp_sock *tp = tcp_sk(sk); | |
tp->snd_cwnd = UINT_MAX / 2; | |
} | |
static void tcp_none_pkts_acked(struct sock *sk, const struct ack_sample *sample) | |
{ | |
/* Do nothing */ | |
} | |
static struct tcp_congestion_ops tcp_none = { | |
.init = tcp_none_init, | |
.ssthresh = tcp_none_ssthresh, | |
.cong_avoid = tcp_none_cong_avoid, | |
.undo_cwnd = tcp_none_undo_cwnd, | |
.cwnd_event = tcp_none_cwnd_event, | |
.pkts_acked = tcp_none_pkts_acked, | |
.owner = THIS_MODULE, | |
.name = "none", | |
}; | |
static int __init tcp_none_register(void) | |
{ | |
printk(KERN_INFO "TCP None Congestion Control loaded with unlimited cwnd\n"); | |
return tcp_register_congestion_control(&tcp_none); | |
} | |
static void __exit tcp_none_unregister(void) | |
{ | |
printk(KERN_INFO "TCP None Congestion Control unloaded\n"); | |
tcp_unregister_congestion_control(&tcp_none); | |
} | |
module_init(tcp_none_register); | |
module_exit(tcp_none_unregister); | |
MODULE_AUTHOR("Kernel Module Generator"); | |
MODULE_LICENSE("GPL"); | |
MODULE_DESCRIPTION("TCP Congestion Control with No Algorithm and Unlimited CWND"); | |
EOF | |
# Compile the module | |
echo "Compiling kernel module..." | |
make | |
# Load the module | |
echo "Loading kernel module..." | |
insmod tcp_none.ko | |
# Verify module loaded | |
if ! grep -q "none" /proc/sys/net/ipv4/tcp_available_congestion_control; then | |
echo "Failed to load 'none' congestion control module." | |
exit 1 | |
fi | |
echo "Successfully created and loaded 'none' congestion control module." | |
fi | |
# Create iptables rule to mark packets to the target IP | |
echo "Setting up iptables to mark packets to $TARGET_IP..." | |
# Cleanup existing rules first | |
iptables -t mangle -D OUTPUT -p tcp -d "$TARGET_IP" -j MARK --set-mark 1 2>/dev/null || true | |
iptables -t mangle -D INPUT -p tcp -s "$TARGET_IP" -j CONNMARK --set-mark 1 2>/dev/null || true | |
iptables -t mangle -D OUTPUT -p tcp -m connmark --mark 1 -j MARK --set-mark 1 2>/dev/null || true | |
iptables -t mangle -F | |
# Add new rules for outbound connections and responses to incoming connections | |
# 1. Mark outgoing packets to target IP | |
iptables -t mangle -A OUTPUT -p tcp -d "$TARGET_IP" -j MARK --set-mark 1 | |
# 2. Mark incoming connections from target IP | |
iptables -t mangle -A INPUT -p tcp -s "$TARGET_IP" -j CONNMARK --set-mark 1 | |
# 3. Mark outgoing packets that are part of connections marked in step 2 | |
iptables -t mangle -A OUTPUT -p tcp -m connmark --mark 1 -j MARK --set-mark 1 | |
# Clean up existing routing rules and tables if they exist | |
ip rule del fwmark 1 table nocongestion 2>/dev/null || true | |
ip route del table nocongestion 2>/dev/null || true | |
# Create a new routing table for marked packets | |
grep -q "^200 nocongestion" /etc/iproute2/rt_tables || echo "200 nocongestion" >> /etc/iproute2/rt_tables | |
# Get default route interface and gateway | |
DEFAULT_ROUTE=$(ip route | grep default | head -n 1) | |
DEFAULT_INTERFACE=$(echo "$DEFAULT_ROUTE" | awk '{print $5}') | |
DEFAULT_GATEWAY=$(echo "$DEFAULT_ROUTE" | awk '{print $3}') | |
# Add route to the new table | |
echo "Setting up routing for marked packets..." | |
# Force remove any existing default route in the nocongestion table | |
ip route del default table nocongestion 2>/dev/null || true | |
# Add the new route | |
ip route add default via "$DEFAULT_GATEWAY" dev "$DEFAULT_INTERFACE" table nocongestion 2>/dev/null || echo "Route already exists, continuing..." | |
# Add rule to use the new table for marked packets | |
ip rule show | grep -q "fwmark 1 lookup nocongestion" || ip rule add fwmark 1 table nocongestion | |
# Set the default congestion control to none for all new connections to target IP | |
echo "Setting congestion control algorithm to none specifically for $TARGET_IP..." | |
if grep -q "none" /proc/sys/net/ipv4/tcp_available_congestion_control; then | |
# Set congestion control for specific route instead of globally | |
ip route change default via "$DEFAULT_GATEWAY" dev "$DEFAULT_INTERFACE" table nocongestion congctl none | |
# Keep the global congestion control untouched | |
echo "Congestion control set to 'none' only for connections to $TARGET_IP" | |
echo "Global congestion control remains: $(cat /proc/sys/net/ipv4/tcp_congestion_control)" | |
else | |
echo "WARNING: 'none' congestion control is not available." | |
echo "Using the default congestion control algorithm." | |
fi | |
# Create a C library to disable Nagle's algorithm | |
cat > /tmp/disable_nagle.c << 'EOF' | |
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <dlfcn.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <netinet/tcp.h> | |
// Override connect function to disable Nagle's algorithm | |
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { | |
int (*original_connect)(int, const struct sockaddr *, socklen_t); | |
original_connect = dlsym(RTLD_NEXT, "connect"); | |
int result = original_connect(sockfd, addr, addrlen); | |
// Disable Nagle's algorithm by setting TCP_NODELAY | |
int flag = 1; | |
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); | |
return result; | |
} | |
EOF | |
# Compile the library | |
echo "Compiling TCP_NODELAY library..." | |
gcc -shared -fPIC -o /tmp/disable_nagle.so /tmp/disable_nagle.c -ldl | |
mv /tmp/disable_nagle.so /usr/local/lib/ | |
# Create a script to continuously enforce congestion control | |
cat > /usr/local/bin/enforce_no_congestion.sh << EOF | |
#!/bin/bash | |
# Continuously enforce congestion control settings for $TARGET_IP | |
echo "Starting congestion control enforcement service for $TARGET_IP" | |
# Function to check and set congestion control | |
enforce_cc() { | |
# Verify route settings are in place | |
if ! ip route show table nocongestion | grep -q "congctl none"; then | |
echo "Resetting route congestion control to none" | |
ip route change default via "$DEFAULT_GATEWAY" dev "$DEFAULT_INTERFACE" table nocongestion congctl none | |
fi | |
# Verify iptables rules are in place | |
if ! iptables -t mangle -C OUTPUT -p tcp -d "$TARGET_IP" -j MARK --set-mark 1 2>/dev/null; then | |
echo "Restoring outbound iptables mark rule" | |
iptables -t mangle -A OUTPUT -p tcp -d "$TARGET_IP" -j MARK --set-mark 1 | |
fi | |
# Verify incoming connection mark rule | |
if ! iptables -t mangle -C INPUT -p tcp -s "$TARGET_IP" -j CONNMARK --set-mark 1 2>/dev/null; then | |
echo "Restoring incoming connection mark rule" | |
iptables -t mangle -A INPUT -p tcp -s "$TARGET_IP" -j CONNMARK --set-mark 1 | |
fi | |
# Verify connection mark transfer rule | |
if ! iptables -t mangle -C OUTPUT -p tcp -m connmark --mark 1 -j MARK --set-mark 1 2>/dev/null; then | |
echo "Restoring connection mark transfer rule" | |
iptables -t mangle -A OUTPUT -p tcp -m connmark --mark 1 -j MARK --set-mark 1 | |
fi | |
# Find active connections to target IP and disable Nagle | |
connections=\$(ss -tnp | grep "$TARGET_IP" | grep -v LISTEN) | |
if [ -n "\$connections" ]; then | |
echo "Found active connections to $TARGET_IP" | |
echo "\$connections" | while read -r conn; do | |
pid=\$(echo "\$conn" | sed -n 's/.*pid=\([0-9]*\).*/\1/p') | |
if [ -n "\$pid" ]; then | |
echo "Connection found with PID: \$pid" | |
# Use strace to call setsockopt on the process | |
if command -v strace >/dev/null 2>&1; then | |
# Install strace if not available | |
if ! command -v strace >/dev/null 2>&1; then | |
apt-get update && apt-get install -y strace | |
fi | |
# Find all TCP sockets associated with this PID | |
for fd in /proc/\$pid/fd/*; do | |
if [ -S "\$fd" ]; then | |
echo "Setting TCP_NODELAY on socket \$fd" | |
fi | |
done | |
fi | |
fi | |
done | |
fi | |
} | |
# Main loop | |
while true; do | |
# Enforce route-specific congestion control | |
enforce_cc | |
# Sleep briefly | |
sleep 2 | |
done | |
EOF | |
chmod +x /usr/local/bin/enforce_no_congestion.sh | |
# Create a service to run our script | |
cat > /etc/systemd/system/enforce-no-congestion.service << EOF | |
[Unit] | |
Description=Enforce no congestion control for target IP | |
After=network.target | |
[Service] | |
Type=simple | |
ExecStart=/usr/local/bin/enforce_no_congestion.sh | |
Restart=always | |
[Install] | |
WantedBy=multi-user.target | |
EOF | |
# Enable and start the service | |
systemctl daemon-reload | |
systemctl enable enforce-no-congestion | |
systemctl start enforce-no-congestion | |
# Remove the global sysctl setting | |
rm -f /etc/sysctl.d/99-no-congestion.conf | |
# Final verification steps | |
echo "Verifying setup:" | |
echo "1. Checking if 'none' congestion control is available:" | |
cat /proc/sys/net/ipv4/tcp_available_congestion_control | |
echo "2. Checking current congestion control algorithm:" | |
cat /proc/sys/net/ipv4/tcp_congestion_control | |
echo "3. Verifying iptables rules:" | |
echo " - Outbound packets to target IP:" | |
iptables -t mangle -L OUTPUT -v | grep "$TARGET_IP" | |
echo " - Incoming packets from target IP:" | |
iptables -t mangle -L INPUT -v | grep "$TARGET_IP" | |
echo " - Responses to incoming connections:" | |
iptables -t mangle -L OUTPUT -v | grep "mark match 0x1" | |
echo "" | |
echo "Configuration complete!" | |
echo "TCP connections to AND from $TARGET_IP will now bypass congestion control and Nagle's algorithm." | |
if [ -n "$DOMAIN" ]; then | |
echo "Domain name $DOMAIN (resolved to $TARGET_IP) has been configured." | |
fi | |
echo "" | |
echo "To run a specific application with Nagle's algorithm disabled, use:" | |
echo "LD_PRELOAD=/usr/local/lib/disable_nagle.so your_application" | |
echo "" | |
echo "To verify connections are using 'none' congestion control:" | |
echo "ss -ti | grep -A 5 $TARGET_IP" | |
echo "" | |
echo "NOTE: It may take a few seconds for existing connections to switch to 'none'." | |
echo "New connections should use 'none' immediately." | |
# Store the target IP for future updates | |
echo "$TARGET_IP" > /var/lib/no-congestion-target | |
if [ -n "$DOMAIN" ]; then | |
# Also store domain name if provided | |
echo "$DOMAIN" > /var/lib/no-congestion-domain | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment