通过 wifi 消费

通过 wifi 消费

最近我遇到了一个小问题。我不知不觉地使用了很多 wifi。这真的很烦人。每次我都要支付 60 美元,因为我不知道我用了多少。现在我在问自己,有没有可以下载的程序,或者可以查看我使用了多少 wifi 的程序?比如说,我每天使用 5gb。但我在家里并不孤单,我还有朋友、家人在使用。最后我会再次充值我的 wifi,而且它变得非常昂贵。所以有没有什么方法可以有人给我一个应用程序的名字,让我可以免费下载它,或者有一个小程序可以计算我和我的家人和朋友使用的每一点流量?如果你们能帮我解决这个问题,那就太好了。

答案1

您可以安装 vnstat。我已经使用过它,而且我看到其他人也向您推荐过它。

在您的电脑上安装它非常简单,只需使用sudo apt-get install vnstat终端上的常用命令即可安装它。

那么你可以关注这篇文章:https://oastic.com/how-to-monitor-network-traffic-on-ubuntu-using-vnstat/

这很简单。如果你遇到困难,请告诉我。

答案2

介绍: 此答案适用于充当路由器的 Ubuntu 服务器,其中 WAN(广域网,又称互联网)和 LAN(局域网)之间的所有流量都通过服务器。它与先前的答案,那个答案用于收集一些 WAN 端统计数据,而这个答案用于收集一些客户端统计数据。

警告: 本文使用的方法会快速创建非常大的文件,并且与网络负载有关。有时 CPU 负载也会很大。请谨慎行事,并留有足够的磁盘空间。

方法: 使用 tcpdump 捕获所有数据包流量,并使用一些后处理来提取所需的信息。

sudo tcpdump -i enp2s0 -Z doug -w 'int-%F-%H-%M-%S.bin' -G 3600 -z ./packet_post_processor3

其中:
我的内部 LAN 接口是enp2s0
文件名自动包含日期和时间(需要额外的包,但我记不清是哪个了);
我要求每小时轮换一次文件;
我希望文件所有权等为doug,(普通用户我);
每个文件都由packet_post_processor脚本进行后期处理(这个答案是 3)。

后处理脚本:

#!/bin/dash
#
# packet_post_processor3 Doug Smythies. 2020.11.26
#       Look at client traffic with this version.
#       See also:
#       https://askubuntu.com/questions/1295243/over-wifi-consomation
#
# packet_post_processor2 Doug Smythies. 2017.09.08
#    Edits as required for updated c prgram, and bad sort order.
#    There may be little use in sort by packets count, but for now
#    it remians.
#
# packet_post_processor2 Doug Smythies. 2017.09.01
#    This script will be called from the always running tcpdump.
#    It is called for every binary file rotation.
#    The purpose is to make summary files of things that one
#    may want to investigate in more detail later on.
#
#    This version is for WinEunuuchs2Unix and
# https://askubuntu.com/questions/951783/how-to-find-out-who-is-taking-70-gb-of-data-from-me-each-month
#

#check that the call included the file name, and only the file name, to use.
if [ $# -ne 1 ]
then
  echo "Usage - $0  file-name"
  exit 1
fi

# check that the file actually exists:
if [ ! -f $1 ]
then
  echo "tcpdump binary file $1 does not exist, aborting..."
  exit 1
fi

echo "data extraction 1: All the packets..."
# Note: Using the -e option will ease subsequent bytes per unit time calculations
tcpdump -n -tttt -e -r $1 >all_e.txt

echo "data extraction 2: The client side outgoing normal packets..."
# Note: We might want to check that something important doesn't get missed here.
# Note: replace the fake IP address with your actual client side sub-net IP.
# for smythies.com this is 192.168.111.0/24:
#ver 2
#grep ": XXX\.XXX\.XXX\.XXX\." all_e.txt | grep Flags >outgoing.txt
#ver 3
grep " > 192\.168\.111\." all_e.txt | grep Flags >outgoing.txt

echo "data extraction 3: Make a histogram of the destination IP addresses by packets..."
# Note: use field 13

cut -d" " -f13 outgoing.txt | sed 's/.[^.]*$//' | sort | uniq -c | sort -g >outhisto.txt

# Phase 2: Maximum packet count might not mean maximum byte count, so figure out maximum byte count

echo "data extraction 4: Sort the outgoing file by destination IP address."
LC_ALL=C sort -k 13 <outgoing.txt >outgoing.srt

echo "data extraction 5: Now, calculate bytes per IP and bytes per IP/16 and make sorted historgrams"
# Note: There might be some clever awk or whatever way to do this, but I have a c program.
./tcpdump_bytes outgoing.srt outb.txt out16.txt
sort --general-numeric-sort <outb.txt >$1.txt
sort --general-numeric-sort <out16.txt >$1.16.txt

# Leave the intermediate files, just for now, while we debug.
# However, and for the huge .bin file, only keep it if really needed. Uncomment to delete.
rm $1
#
# packet_post_process. End.

脚本中调用的 c 程序:

/*****************************************************************************
*
* tcpdump_bytes.c 2017.09.08 Smythies
*       By sorting the input file before running this program, it can do bytes
*       per IP all on its own, and in one pass through the file. At this time,
*       it is for outgoing only. A future revision will add command line
*       options for incoming and such.
*       Might as well group by 1st 2 IP address bytes at the same time,
*       i.e. for some (not all) of those multiple IP situations.
*
* tcpdump_bytes.c 2017.09.01 Smythies
*       Count the bytes for all the packets in the passed file.
*       See also tcpdump_extract.c, from which this was taken.
*       This program is very quite, just printing bytes, unless there
*       is some error. The idea is that is part of something bigger and
*       therefore extra verbosity would just get in the way.
*
*       Note: The input tcpdump file needs to have been done
*             with the -e option.
*
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH 2000  /* maximum line length */

void main(int argc, char **argv){

   char in_buffer[MAX_LENGTH];
   char *infile, *outfile1, *outfile2;
   char *index, *index2;
   FILE *inf, *out1, *out2;
   unsigned current_bytes, sip3, sip2, sip1, sip0, sport, dip3, dip2, dip1, dip0, dport;
   unsigned dest_ip, dest_ip_16, dest_ip_old, dest_ip_16_old;
   unsigned num_lines, num_ips, num_16s;
   unsigned long long total_bytes, total_bytes_16;

   switch(argc){
   case 4:
      infile = argv[1];
      outfile1 = argv[2];
      outfile2 = argv[3];
      break;
   default:
      printf("tcpdump_bytes infile outfile1 outfile2\n");
      printf("  parse outgoing bytes per IP out of a sorted tcpdump file where the -e option was used.\n");
      printf("  infile is sorted tcpdump output file; oufile1 is bytes per IP; outfile 2 is bytes per IP/16.\n");
      exit(-1);
   } /* endcase */

   if((inf = fopen(infile, "rt")) == NULL){
      printf("Unable to open input file '%s'\n", infile);
      exit(-1);
   } /* endif */
   if((out1 = fopen(outfile1, "wt")) == NULL){
      printf("Error opening output file '%s'\n", outfile1);
      exit(-1);
   } /* endif */
   if((out2 = fopen(outfile2, "wt")) == NULL){
      printf("Error opening output file '%s'\n", outfile2);
      exit(-1);
   } /* endif */

   total_bytes = 0;
   total_bytes_16 = 0;
   dest_ip_old = 0;
   dest_ip_16_old = 0;
   num_lines = 0;
   num_ips = 0;
   num_16s = 0;

   while((fgets(in_buffer, MAX_LENGTH, inf)) != NULL){       /* do infile line at a time */
      num_lines++;

      if((index = strstr(in_buffer, "), length ")) != NULL){ /* find search string if it is there, then parse the data */
         sscanf(index, "), length %u: %u.%u.%u.%u.%u > %u.%u.%u.%u.%u:",
            &current_bytes,
            &sip3, &sip2, &sip1, &sip0,
            &sport,
            &dip3, &dip2, &dip1, &dip0,
            &dport);
      } else {
         printf("tcpdump_bytes: Got an odd line: %s", in_buffer);
      } /* endif */
      dest_ip_16 = (dip3 << 24) + (dip2 << 16);
      dest_ip = dest_ip_16 + (dip1 << 8) + dip0;
//    printf("debug: B: %u  S: %u.%u.%u.%u.%u  D: %u.%u.%u.%u.%u  %u  %u\n", current_bytes, sip3, sip2, sip1, sip0, sport, dip3, dip2, dip1, dip0, dport, dest_ip, dest_ip_16);

      if(dest_ip != dest_ip_old){
         if(total_bytes != 0){
            fprintf(out1, "%llu %u.%u.%u.%u\n", total_bytes, (dest_ip_old >> 24) & 0xff, (dest_ip_old >> 16) & 0xff, (dest_ip_old >> 8) & 0xff, dest_ip_old & 0xff);
            total_bytes = 0;
         } /* endif */
         dest_ip_old = dest_ip;
         num_ips++;
      } /* endif */
      total_bytes = total_bytes + (unsigned long long) current_bytes;

      if(dest_ip_16 != dest_ip_16_old){
         if(total_bytes_16 != 0){
            fprintf(out2, "%llu %u.%u.0.0/16\n", total_bytes_16, (dest_ip_16_old >> 24) & 0xff, (dest_ip_16_old >> 16) & 0xff);
            total_bytes_16 = 0;
         } /* endif */
         dest_ip_16_old = dest_ip_16;
         num_16s++;
      } /* endif */
      total_bytes_16 = total_bytes_16 + (unsigned long long) current_bytes;
   } /* endwhile */

   /* don't forget to output the last data */
   if(total_bytes != 0){
      fprintf(out1, "%llu %u.%u.%u.%u\n", total_bytes, dip3, dip2, dip1, dip0);
   } else {
      printf("tcpdump_bytes: Something is wrong. Last IP address has no bytes.\n");
   } /* endif */

   if(total_bytes_16 != 0){
      fprintf(out2, "%llu %u.%u.0.0/16\n", total_bytes_16, dip3, dip2);
   } else {
      printf("tcpdump_bytes: Something is wrong. Last IP/16 address has no bytes.\n");
   } /* endif */

   fclose(inf);
   fclose(out1);
   fclose(out2);
   printf("tcpdump_bytes: Done. Processed %d lines and %d IP addresses and %d /16 addresses\n", num_lines, num_ips, num_16s);
} /* endprogram */

后处理脚本的简要概述:
首先,将二进制 tcpdump 文件转换为每个数据包摘要文本。示例(我的 LAN 子网是 192.168.111.0/24,路由器是 192.168.111.1):

2020-11-26 12:16:40.077187 64:1c:ae:dc:c0:d3 > 00:19:b9:0d:af:fa, ethertype IPv4 (0x0800), length 60: 192.168.111.123.36953 > 69.164.31.0.443: Flags [R], seq 4022180665, win 0, length 0
2020-11-26 12:16:40.077210 64:1c:ae:dc:c0:d3 > 00:19:b9:0d:af:fa, ethertype IPv4 (0x0800), length 60: 192.168.111.123.36953 > 69.164.31.0.443: Flags [R], seq 4022180665, win 0, length 0
2020-11-26 12:16:40.077225 64:1c:ae:dc:c0:d3 > 00:19:b9:0d:af:fa, ethertype IPv4 (0x0800), length 60: 192.168.111.123.36953 > 69.164.31.0.443: Flags [R], seq 4022180665, win 0, length 0
2020-11-26 12:16:40.077241 64:1c:ae:dc:c0:d3 > 00:19:b9:0d:af:fa, ethertype IPv4 (0x0800), length 66: 192.168.111.123.39503 > 99.81.137.214.443: Flags [.], ack 909, win 998, options [nop,nop,TS val 117576 ecr 459725584], length 0
2020-11-26 12:16:40.077251 00:19:b9:0d:af:fa > 64:1c:ae:dc:c0:d3, ethertype IPv4 (0x0800), length 504: 192.168.111.1.53 > 192.168.111.123.49124: 20771 5/4/15 A 8.251.162.11, A 8.240.108.139, A 8.240.90.139, A 8.240.93.139, A 8.240.102.11 (462)
2020-11-26 12:16:40.077412 00:19:b9:0d:af:fa > 64:1c:ae:dc:c0:d3, ethertype IPv4 (0x0800), length 500: 192.168.111.1.53 > 192.168.111.123.49124: 8356 5/4/11 AAAA 2001:1900:2352:104f::1, AAAA 2001:1900:23b2:11::1, AAAA 2001:1900:2304:5f06::1, AAAA 2001:1900:23b2:1::1, AAAA 2001:1900:2304:7055::1 (458)
2020-11-26 12:16:40.235369 00:19:b9:0d:af:fa > 64:1c:ae:dc:c0:d3, ethertype ARP (0x0806), length 42: Request who-has 192.168.111.123 tell 192.168.111.1, length 28
2020-11-26 12:16:40.237464 64:1c:ae:dc:c0:d3 > 01:00:5e:00:00:07, ethertype IPv4 (0x0800), length 246: 192.168.111.123.8001 > 224.0.0.7.8001: UDP, length 204
2020-11-26 12:16:40.237479 64:1c:ae:dc:c0:d3 > 00:19:b9:0d:af:fa, ethertype IPv4 (0x0800), length 74: 192.168.111.123.33547 > 8.251.162.11.443: Flags [S], seq 2516382973, win 29200, options [mss 1460,sackOK,TS val 117612 ecr 0,nop,wscale 7], length 0
2020-11-26 12:16:40.237508 64:1c:ae:dc:c0:d3 > 00:19:b9:0d:af:fa, ethertype ARP (0x0806), length 60: Reply 192.168.111.123 is-at 64:1c:ae:dc:c0:d3, length 46
2020-11-26 12:16:40.308884 00:19:b9:0d:af:fa > 64:1c:ae:dc:c0:d3, ethertype IPv4 (0x0800), length 74: 8.251.162.11.443 > 192.168.111.123.33547: Flags [S.], seq 829843053, ack 2516382974, win 65160, options [mss 1460,sackOK,TS val 1958034067 ecr 117612,nop,wscale 7], length 0
2020-11-26 12:16:40.311459 64:1c:ae:dc:c0:d3 > 00:19:b9:0d:af:fa, ethertype IPv4 (0x0800), length 66: 192.168.111.123.33547 > 8.251.162.11.443: Flags [.], ack 1, win 229, options [nop,nop,TS val 117669 ecr 1958034067], length 0
2020-11-26 12:16:40.841355 00:19:b9:0d:af:fa > 00:21:9b:f9:21:26, ethertype IPv4 (0x0800), length 1514: 173.180.45.3.22 > 192.168.111.101.61404: Flags [.], seq 9584:11044, ack 161, win 7733, length 1460
2020-11-26 12:16:40.841375 00:19:b9:0d:af:fa > 00:21:9b:f9:21:26, ethertype IPv4 (0x0800), length 162: 173.180.45.3.22 > 192.168.111.101.61404: Flags [P.], seq 11044:11152, ack 161, win 7733, length 108
2020-11-26 12:16:40.842302 00:21:9b:f9:21:26 > 00:19:b9:0d:af:fa, ethertype IPv4 (0x0800), length 60: 192.168.111.101.61404 > 173.180.45.3.22: Flags [.], ack 11152, win 1026, length 0

示例中特意包含一对 ARP 数据包,以显示将被排除在进一步处理之外的内容。
还有一些其他令人讨厌的数据包类型也将被排除在进一步处理之外。请注意每行显示的两个长度,第一个是线路上的字节数,第二个是有效载荷长度。我们需要线路上的字节数,这就是我们在 tcpdump 中使用 -e 选项的原因。

其次,可以通过查找“:192.168.111.”来唯一地识别传出的 LAN 数据包,因此使用 grep 提取所有传出的数据包(不包括 ARP 和 ICMP)。

第三,使用空格作为分隔符,字段 13 是目标 IP 地址,因此使用一组复杂的管道命令来提取、计数和排序目标 IP 地址数据包。

第四,按目标 IP 地址对传出的数据包进行排序。
第五,使用 c 程序计算每个 IP 的字节数和每个 IP/16 的字节数,并将输出排序为直方图。

几个小时的例子:

doug@DOUG-64:~/tcpdump/per-client-test$ cat int-2020-11-26-10-16-32.bin.txt
16004 192.168.111.18
109288 192.168.111.1
247652 192.168.111.5
319432 192.168.111.19
11535118 192.168.111.101
doug@DOUG-64:~/tcpdump/per-client-test$ cat int-2020-11-26-10-16-32.bin.16.txt
12227494 192.168.0.0/16

这意味着在 2020.11.26 10:16:32 至 11:16:32 这一小时内,有 12,227,494 字节发送到 LAN 上的各个客户端,每个客户端都有详细的细分。请注意,发送到 192.168.111.1 的 109,288 字节实际上是从 LAN 发送到路由器本身的字节。观察发现,到目前为止,该小时内发送量最多的是客户端 192.168.111.101。

示例 2:

doug@DOUG-64:~/tcpdump/per-client-test$ cat int-2020-11-26-19-28-43.bin.txt
6605 192.168.111.1
121859 192.168.111.18
213614 192.168.111.20
257793 192.168.111.5
291138 192.168.111.19
2600309 192.168.111.123
7904391 192.168.111.101
2319210919 192.168.111.121
doug@DOUG-64:~/tcpdump/per-client-test$ cat int-2020-11-26-19-28-43.bin.16.txt
2330606628 192.168.0.0/16
doug@DOUG-64:~/tcpdump/per-client-test$ cat int-2020-11-26-20-28-43.bin.txt
4616 192.168.111.1
22196 192.168.111.20
75687 192.168.111.18
257152 192.168.111.5
346799 192.168.111.19
516269 192.168.111.123
8250344 192.168.111.101
2190976161 192.168.111.121
doug@DOUG-64:~/tcpdump/per-client-test$ cat int-2020-11-26-20-28-43.bin.16.txt
2200449224 192.168.0.0/16
doug@DOUG-64:~/tcpdump/per-client-test$ nslookup 192.168.111.121
Server:         127.0.0.1
Address:        127.0.0.1#53

121.111.168.192.in-addr.arpa    name = lg55.smythies.com.

因此,55 英寸 LG 智能电视在这天晚上 7:28 到 9:28 之间使用了大量互联网。例如一部 Netflix 电影。(2.3e9 和 2.2e9 字节。)

问题
默认情况下,apparmor 不允许执行 tcpdump 后处理命令。可能有更好、更安全的方法,但我这样做是为了能够继续前进(将 apparmor 设置为投诉模式):

doug@DOUG-64:~/tcpdump/per-client-test$ sudo grep tcpdump /sys/kernel/security/apparmor/profiles
/usr/sbin/tcpdump (enforce)
doug@DOUG-64:~/tcpdump/per-client-test$ sudo aa-complain /usr/sbin/tcpdump
Setting /usr/sbin/tcpdump to complain mode.
doug@DOUG-64:~/tcpdump/per-client-test$ sudo grep tcpdump /sys/kernel/security/apparmor/profiles
/usr/sbin/tcpdump (complain)

编辑:我发现这个客户总结工具非常有用。

相关内容