MoniTraffic.sh
· 2.4 KiB · Bash
Raw
#!/bin/bash
function monitor_traffic() {
if [ -z "$1" ]; then
echo "Usage: $0 <network_interface>"
echo "Available network interfaces:"
ip link show | awk -F': ' '/^[0-9]+: /{print $2}'
exit 1
fi
INTERFACE=$1
DURATION=10 # Duration in seconds for each capture window
# Output header only once
printf "IP Address\tDownload (bytes)\tUpload (bytes)\n"
# Handle SIGINT (Ctrl+C) to gracefully exit the loop
trap "echo 'Exiting...'; exit 0" SIGINT
while true; do
# Temp file to store tcpdump output
TMP_FILE=$(mktemp)
trap "rm -f $TMP_FILE" EXIT # Ensure cleanup on exit or interruption
# Capture IPv4 traffic on the specified interface for the specified duration
sudo timeout $DURATION tcpdump -i $INTERFACE -nn -q -tt 'ip' > $TMP_FILE 2>/dev/null
# Calculate traffic statistics
awk '
/IP/ {
# Extract source and destination IPs using a stricter pattern to ensure only IPs are captured
if (match($3, /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)) {
src_ip = substr($3, RSTART, RLENGTH)
}
if (match($5, /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)) {
dst_ip = substr($5, RSTART, RLENGTH)
}
# Calculate packet size (bytes) - field 8 (better validation)
size = $NF
if (size ~ /^[0-9]+$/) {
# Count download (dst_ip) and upload (src_ip) for traffic
download[dst_ip] += size
upload[src_ip] += size
}
}
END {
# Create a combined total_bytes array for sorting
for (ip in download) {
total_bytes[ip] = download[ip] + upload[ip]
}
# Sort IPs by total bytes in descending order
n = asorti(total_bytes, sorted_ips, "@val_num_desc")
for (i = 1; i <= n; i++) {
ip = sorted_ips[i]
download_data = download[ip] > 0 ? download[ip] : 0
upload_data = upload[ip] > 0 ? upload[ip] : 0
printf "%-15s\t%-15d\t%-15d\n", ip, download_data, upload_data
}
}' $TMP_FILE
# Print separator line
echo "======================================="
# Clean up the temporary file
rm -f $TMP_FILE
done
}
# Call function with passed argument (network interface)
monitor_traffic $1
1 | #!/bin/bash |
2 | |
3 | function monitor_traffic() { |
4 | if [ -z "$1" ]; then |
5 | echo "Usage: $0 <network_interface>" |
6 | echo "Available network interfaces:" |
7 | ip link show | awk -F': ' '/^[0-9]+: /{print $2}' |
8 | exit 1 |
9 | fi |
10 | |
11 | INTERFACE=$1 |
12 | DURATION=10 # Duration in seconds for each capture window |
13 | |
14 | # Output header only once |
15 | printf "IP Address\tDownload (bytes)\tUpload (bytes)\n" |
16 | |
17 | # Handle SIGINT (Ctrl+C) to gracefully exit the loop |
18 | trap "echo 'Exiting...'; exit 0" SIGINT |
19 | |
20 | while true; do |
21 | # Temp file to store tcpdump output |
22 | TMP_FILE=$(mktemp) |
23 | trap "rm -f $TMP_FILE" EXIT # Ensure cleanup on exit or interruption |
24 | |
25 | # Capture IPv4 traffic on the specified interface for the specified duration |
26 | sudo timeout $DURATION tcpdump -i $INTERFACE -nn -q -tt 'ip' > $TMP_FILE 2>/dev/null |
27 | |
28 | # Calculate traffic statistics |
29 | awk ' |
30 | /IP/ { |
31 | # Extract source and destination IPs using a stricter pattern to ensure only IPs are captured |
32 | if (match($3, /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)) { |
33 | src_ip = substr($3, RSTART, RLENGTH) |
34 | } |
35 | if (match($5, /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)) { |
36 | dst_ip = substr($5, RSTART, RLENGTH) |
37 | } |
38 | |
39 | # Calculate packet size (bytes) - field 8 (better validation) |
40 | size = $NF |
41 | if (size ~ /^[0-9]+$/) { |
42 | # Count download (dst_ip) and upload (src_ip) for traffic |
43 | download[dst_ip] += size |
44 | upload[src_ip] += size |
45 | } |
46 | } |
47 | END { |
48 | # Create a combined total_bytes array for sorting |
49 | for (ip in download) { |
50 | total_bytes[ip] = download[ip] + upload[ip] |
51 | } |
52 | |
53 | # Sort IPs by total bytes in descending order |
54 | n = asorti(total_bytes, sorted_ips, "@val_num_desc") |
55 | |
56 | for (i = 1; i <= n; i++) { |
57 | ip = sorted_ips[i] |
58 | download_data = download[ip] > 0 ? download[ip] : 0 |
59 | upload_data = upload[ip] > 0 ? upload[ip] : 0 |
60 | printf "%-15s\t%-15d\t%-15d\n", ip, download_data, upload_data |
61 | } |
62 | }' $TMP_FILE |
63 | |
64 | # Print separator line |
65 | echo "=======================================" |
66 | |
67 | # Clean up the temporary file |
68 | rm -f $TMP_FILE |
69 | done |
70 | } |
71 | |
72 | # Call function with passed argument (network interface) |
73 | monitor_traffic $1 |
74 |
Program.cs
· 3.2 KiB · C#
Raw
//<PackageReference Include="Aiursoft.AiurObserver.Command" Version="8.0.4" />
//<PackageReference Include="Aiursoft.AiurObserver.Extensions" Version="8.0.3" />
//<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" />
using Aiursoft.AiurObserver;
using Aiursoft.AiurObserver.Command;
using Microsoft.Extensions.Logging;
using Aiursoft.AiurObserver.Extensions;
namespace Moni;
public abstract class Program
{
private BlockRule[] _rules = new[]
{
// 8MiB/s, 80MiB in 10 seconds
new BlockRule
{
MaxBytesTransferred = 0x500_0000,
IntervalSeconds = 10
},
// 6MiB/s, 360MiB in 60 seconds
new BlockRule
{
MaxBytesTransferred = 0x1680_0000,
IntervalSeconds = 60
},
// 5MiB/s, 1500MiB in 300 seconds (5 minutes)
new BlockRule
{
MaxBytesTransferred = 0x5DC0_0000,
IntervalSeconds = 300
},
// 4MiB/s, 2400MiB in 600 seconds (10 minutes)
new BlockRule
{
MaxBytesTransferred = 0x9600_0000,
IntervalSeconds = 600
},
// 3MiB/s, 3600MiB in 1200 seconds (20 minutes)
new BlockRule
{
MaxBytesTransferred = 0xE10_0000,
IntervalSeconds = 1200
}
};
private static Dictionary<string, long> IpTrafficUsage { get; } = new();
public static async Task Main(string[] args)
{
if (args.Length != 1)
{
Console.WriteLine("Please provide the network interface name.");
return;
}
var interfaceName = args[0];
var logger = LoggerFactory.Create(logging => logging.AddConsole()).CreateLogger<LongCommandRunner>();
var runner = new LongCommandRunner(logger);
// Returns every 10 seconds
runner.Output.InNewThread().Subscribe(OnLog);
await runner.Run(
bin: "/usr/bin/bash",
arg: $"/usr/local/bin/moninet {interfaceName}",
path: "/");
}
private static Task OnLog(string rawOutput)
{
var outputLines = rawOutput.Split("\n");
foreach (var line in outputLines.Select(outputLine => outputLine.Trim()))
{
if (line.StartsWith("IP Address")) continue;
if (line.StartsWith("===")) continue;
var parts = line.Split(" ", StringSplitOptions.RemoveEmptyEntries)
.Select(part => part.Trim())
.ToArray();
if (parts.Length != 3) continue;
var ipAddr = parts[0];
var download = long.Parse(parts[1]);
var upload = long.Parse(parts[2]);
Console.WriteLine($"In the past 10 seconds, remote IP {ipAddr} downloaded {download} bytes and uploaded {upload} bytes.");
var totalTraffic = download + upload;
IpTrafficUsage[ipAddr] = IpTrafficUsage.TryGetValue(ipAddr, out var usage) ? usage + totalTraffic : totalTraffic;
}
return Task.CompletedTask;
}
}
public class BlockRule
{
public long MaxBytesTransferred { get; set; }
public int IntervalSeconds { get; set; }
}
1 | //<PackageReference Include="Aiursoft.AiurObserver.Command" Version="8.0.4" /> |
2 | //<PackageReference Include="Aiursoft.AiurObserver.Extensions" Version="8.0.3" /> |
3 | //<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.1" /> |
4 | |
5 | using Aiursoft.AiurObserver; |
6 | using Aiursoft.AiurObserver.Command; |
7 | using Microsoft.Extensions.Logging; |
8 | using Aiursoft.AiurObserver.Extensions; |
9 | |
10 | namespace Moni; |
11 | |
12 | public abstract class Program |
13 | { |
14 | private BlockRule[] _rules = new[] |
15 | { |
16 | // 8MiB/s, 80MiB in 10 seconds |
17 | new BlockRule |
18 | { |
19 | MaxBytesTransferred = 0x500_0000, |
20 | IntervalSeconds = 10 |
21 | }, |
22 | // 6MiB/s, 360MiB in 60 seconds |
23 | new BlockRule |
24 | { |
25 | MaxBytesTransferred = 0x1680_0000, |
26 | IntervalSeconds = 60 |
27 | }, |
28 | // 5MiB/s, 1500MiB in 300 seconds (5 minutes) |
29 | new BlockRule |
30 | { |
31 | MaxBytesTransferred = 0x5DC0_0000, |
32 | IntervalSeconds = 300 |
33 | }, |
34 | // 4MiB/s, 2400MiB in 600 seconds (10 minutes) |
35 | new BlockRule |
36 | { |
37 | MaxBytesTransferred = 0x9600_0000, |
38 | IntervalSeconds = 600 |
39 | }, |
40 | // 3MiB/s, 3600MiB in 1200 seconds (20 minutes) |
41 | new BlockRule |
42 | { |
43 | MaxBytesTransferred = 0xE10_0000, |
44 | IntervalSeconds = 1200 |
45 | } |
46 | }; |
47 | |
48 | private static Dictionary<string, long> IpTrafficUsage { get; } = new(); |
49 | |
50 | public static async Task Main(string[] args) |
51 | { |
52 | if (args.Length != 1) |
53 | { |
54 | Console.WriteLine("Please provide the network interface name."); |
55 | return; |
56 | } |
57 | |
58 | var interfaceName = args[0]; |
59 | |
60 | var logger = LoggerFactory.Create(logging => logging.AddConsole()).CreateLogger<LongCommandRunner>(); |
61 | var runner = new LongCommandRunner(logger); |
62 | |
63 | // Returns every 10 seconds |
64 | runner.Output.InNewThread().Subscribe(OnLog); |
65 | |
66 | await runner.Run( |
67 | bin: "/usr/bin/bash", |
68 | arg: $"/usr/local/bin/moninet {interfaceName}", |
69 | path: "/"); |
70 | } |
71 | |
72 | private static Task OnLog(string rawOutput) |
73 | { |
74 | var outputLines = rawOutput.Split("\n"); |
75 | foreach (var line in outputLines.Select(outputLine => outputLine.Trim())) |
76 | { |
77 | if (line.StartsWith("IP Address")) continue; |
78 | if (line.StartsWith("===")) continue; |
79 | var parts = line.Split(" ", StringSplitOptions.RemoveEmptyEntries) |
80 | .Select(part => part.Trim()) |
81 | .ToArray(); |
82 | if (parts.Length != 3) continue; |
83 | |
84 | var ipAddr = parts[0]; |
85 | var download = long.Parse(parts[1]); |
86 | var upload = long.Parse(parts[2]); |
87 | Console.WriteLine($"In the past 10 seconds, remote IP {ipAddr} downloaded {download} bytes and uploaded {upload} bytes."); |
88 | var totalTraffic = download + upload; |
89 | IpTrafficUsage[ipAddr] = IpTrafficUsage.TryGetValue(ipAddr, out var usage) ? usage + totalTraffic : totalTraffic; |
90 | } |
91 | |
92 | return Task.CompletedTask; |
93 | } |
94 | } |
95 | |
96 | public class BlockRule |
97 | { |
98 | public long MaxBytesTransferred { get; set; } |
99 | |
100 | public int IntervalSeconds { get; set; } |
101 | } |
install.sh
· 161 B · Bash
Raw
sudo wget https://gist.aiursoft.cn/anduin/e66120d03c9945dda921d0fb2039cb38/raw/HEAD/MoniTraffic.sh -O /usr/local/bin/moninet
sudo chmod +x /usr/local/bin/moninet
1 | sudo wget https://gist.aiursoft.cn/anduin/e66120d03c9945dda921d0fb2039cb38/raw/HEAD/MoniTraffic.sh -O /usr/local/bin/moninet |
2 | sudo chmod +x /usr/local/bin/moninet |