实验配置

实验使用两个虚拟机同时挂在主机NAT服务上互相通信来实现,使用系统:Ubuntu22.04desktop和Ubuntu16.04server。

安装两个系统后,查看两个虚拟机的网络地址,查看是否可以互相ping通。

image-20250402145538871

image-20250402145607250

以太网ARP请求测试

使用sftp将老师提供的示例代码上传至192.168.81.51的机器

安装gcc:

sudo apt-get install gcc

编译发送请求的代码:

sudo gcc arp_send_request.c -o arp_send_request

同时编译接收端的代码:

sudo gcc arp_recv_request_and_send_reply.c -o arp_test

两机一个监听一个发送:(51用来发送请求,50用来监听与回复请求)

image-20250402155325384

可以看到192.168.81.51服务器成功获取到了192.168.81.50的MAC地址。

同时可以通过wireshark捕获虚拟机网卡的包来查看到ARP协议记录:

image-20250402160043722

可以看到由于ARP请求包为广播包,所以我们使用主机抓包可以抓取到请求包,但由于应答包为单播包,所以无法抓取到,此时我们可以开启虚拟机上的wireshark,即可抓取到应答包。

或者我们可以测试抓取网关的包,此时网关的包会过主机,所以就可以被抓取到。

image-20250412144256274

网络ping功能测试

编译并运行老师提供的ping命令代码:

gcc ping.c -o ping && sudo ./ping 192.168.81.52

可以看到收到应答报文,并可以在wireshark中抓包抓到响应的请求与响应。

image-20250412145735824

在wireshark中可以看到每个请求包和响应包的编号,并且可以定位到一组发送和请求。

image-20250412150712937

可以看到分组内容和已知PING格式是相同的。

将代码中的数据长修改为60。

int datalen = 60;

重新启动程序,可以看到每个ping的数据长度变为68(60字节的数据长度和8字节的头部)。其中,8字节为固定的时间戳,数据长度从以往的48字节变为52字节。

image-20250412151646488

可以看到目前的ping请求的数据部分没有内容,尝试在其中填充内容,将代码修改为:

gettimeofday((struct timeval *)icmp->icmp_data, NULL);
for (int i = 0; i < 0x34; i++)
{
    icmp->icmp_data[i + 8] = i;
}
len = 8+datalen;
icmp->icmp_cksum = 0;
icmp->icmp_cksum = in_cksum((u_short *)icmp, len);

重新编译运行,可以看到数据部分被填充了对应的数:

image-20250412152456019

网络Traceroute功能测试

编译运行老师提供的程序:

ping www.baidu.com
gcc main.c traceroute.c -o traceroute && ./traceroute -I 39.156.70.46

由于VMWare的NAT是一个七层的NAT,NAT转换了数据流的源地址,转成了宿主机的无线网卡的地址,导致无法收到路由器的包,所以路过的所有都无法显示出来,如下图:

image-20250412164244422

将虚拟机网络模式修改为桥接,重新启动虚拟机,可以看到traceroute可以正常工作。

image-20250412165928660

使用wireshark进行抓包,可以看到ttl逐渐从1增加到11,这与我们使用traceroute得到的结果是一致的。

image-20250412170745133

此处分析一下TTL=1的数据包

TTL=1的请求数据包:

image-20250412171536337

可以得到以下信息 .

IP 层信息

IP 版本: IPv4 总长度: 84bytes, 包括 IP 首部和数据的总长度 标识字段: 0x8d88, 数据包的分片标识符, 用于 IP 分片 标志(Flags): 0x40,表示此包未设置分片标志 片偏移(Fragment Offset): 0, 说明这是一个未分片的数据包 IP地址 源IP地址: 192.168.10.23,这是发出Echo Request的桥接虚拟机的 IP 地址 目标地址: 39.156.70.46,这是目标主机的 IP 地址, 即我们希望测试连通性的设备 TTL=1:表示这是请求数据包的初始 TTL 值, 经过第一个路由设备时将被递减为 0, 因此路由器会返回Time-to-live exceeded 响应

ICMP 协议信息

ICMP类型:8,表示这是一个 ICMP Echo Request 数据包。 校验和:0xc92f,用于校验数据包内容的完整性。

总结

从图中下方显示的信息可以清楚地看到: 此数据包是由源地址192.168.10.23发出的Echo Request, 目标是39.156.70.46 数据包的 TTL 为 1, 是tracert的第一个跳数, 尝试探测第一个路由器的地址和路径延迟 IP 层和以太网层的详细信息展示了路由和传输的基本特性, 同时包含数据完整性校验字段

TTL=1的返回数据包:

image-20250412172239626

可以得到以下信息 .

IP 层信息

IP 版本: IPv4 标识字段: 0x0000, 数据包的分片标识符, 表明返回的 ICMP 数据包没有被分片 标志(Flags): 0x0,表示此包未设置分片标志 片偏移(Fragment Offset): 0, 说明这是一个未分片的数据包

IP地址

源IP地址:192.168.10.82:这是第一跳设备的 IP 地址(是虚拟机主机的IP地址) 目标地址:192.168.10.23, 这是发送 ICMP 请求的主机的 IP 地址

ICMP协议信息

ICMP类型: 11(Time-to-live exceeded)表示原始数据包的 TTL 已耗尽, 第一跳设备返回了超时消息 校验和: 0xf4ff, 用于用于验证 IP 首部的完整性 嵌套的原始Echo Request 信息: ICMP 消息的负载部分包含了导致 TTL 超时的原始请求包头部和部分数据

TCP/UDP客户/服务程序测试

切换为NAT模式,在192.168.81.52的机器的80端口编译并开启udp_server程序。

gcc udp_server.c -o udp_server && ./udp_server 192.168.81.52 80

192.168.81.50的机器编译并开启udp_client程序,访问开启的服务。

gcc udp_client.c -o udp_client && ./udp_client 192.168.81.52 80

输入数据,即可看到两台机器的访问结果:

image-20250412175055770

192.168.81.52的机器的8081端口编译并开启tcp_server程序。

gcc tcp_server.c -o tcp_server && ./tcp_server 192.168.81.52 8081

192.168.81.50的机器编译并开启tcp_client程序,访问开启的服务。

gcc tcp_client.c -o tcp_client && ./tcp_client 192.168.81.52 8081

输入数据,即可看到两台机器的访问结果:

image-20250412180904223

通过wireshark可以看到完整的tcp通信过程:

image-20250412181540204

经过测试可以看到二者区别:当udp的client服务目标未开启时,是可以正常开启功能的,只是发出的数据包没有回复。而当tcp的服务器未开启时是无法成功握手的,也就无法启动tcp的client服务。

TCP聊天应用程序测试

选用与主机在同网段下的一个树莓派作为服务器运行服务器程序,使用两个虚拟机链接服务器进行聊天测试。

image-20250412191621231

image-20250412191727105

可以看到聊天室运行正常,两台虚拟机可以作为从机登录到网络服务器上进行通信。

测试网络应用平台搭建

同样在树莓派上进行环境搭建,首先安装apache2

apt-get install apache2
systemctl enable apache2
systemctl status apache2

image-20250412193928358

可以看到apache2运行正常,使用虚拟机访问设备,可以看到apache主页。

image-20250412194010436

将老师提供的网页复制到www目录下

image-20250412194803910

登录mysql创建对应的数据库和表,为应用创建一个新用户并且赋予其权限。

image-20250412195830283

修改conn.php中的配置,输入数据库的新用户账号密码。

image-20250412195915994

然后注册账号,登录账号。

image-20250412195931319

image-20250412195934859

image-20250412200040930

问题解决

1.

ubuntu系统使用NAT无法上网的问题,首先需要确保主机上面的VMWare的相关服务处于启动状态:

win+R启动service.msc找到VMWare NAT ServiceVMWare DHCP Service两个服务,确保他们处于正在运行状态,如果不是就手动重启。

image-20250402144213103

接下来来到ubuntu系统上,输入nmcli device status查看当前网络状态,发现ens33网卡处于未启用状态。使用sudo ip link set ens33 up将网卡启动。

image-20250402144517399

再键入ifconfig可以看到ens33网卡已经出现,但是还没有获取到IP地址,此时再输入sudo dhclient ens33重新通过dhcp服务器获取IP地址,再输入ifconfig可以看到已经没有问题了。

image-20250402144759493

2.

编译老师提供的ping命令代码:

gcc ping.c -o ping

可能会出现警告:

ping.c: In function ‘err_doit’:
ping.c:279:38: warning: format not a string literal and no format arguments [-Wformat-security]
  279 |                 syslog(level, (char*)buf);
      |                                      ^~~

是因为syslog函数需要传参是需要格式化字符串。

需要进入ping.c文件中找到err_doit函数,并将其中对应的代码修改为:

if (daemon_proc)
{
    syslog(level, "%s", buf);
}

再次编译便不会报警告。

3.

编译老师提供的traceroute代码发现报错:

/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0x0): multiple definition of `troptions'; /tmp/ccps0vjl.o:(.bss+0x0): first defined here
/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0x10): multiple definition of `sport'; /tmp/ccps0vjl.o:(.bss+0x10): first defined here
/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0x12): multiple definition of `dport'; /tmp/ccps0vjl.o:(.data+0x0): first defined here
/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0x20): multiple definition of `destaddr'; /tmp/ccps0vjl.o:(.bss+0x20): first defined here
/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0x30): multiple definition of `hostname'; /tmp/ccps0vjl.o:(.bss+0x30): first defined here
/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0x40): multiple definition of `sendbuf'; /tmp/ccps0vjl.o:(.bss+0x40): first defined here
/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0x620): multiple definition of `recvbuf'; /tmp/ccps0vjl.o:(.bss+0x620): first defined here
/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0xbfc): multiple definition of `datalen'; /tmp/ccps0vjl.o:(.bss+0xbfc): first defined here
/usr/bin/ld: /tmp/ccnd7Qn4.o:(.bss+0xc00): multiple definition of `alarm_flag'; /tmp/ccps0vjl.o:(.bss+0xc00): first defined here

是由于全局变量定义在了头文件中,需要进行修改:

traceroute.h中的如下代码改到traceroute.c中:

struct troptions    troptions;
uint16_t    sport, dport;           //源端端口和目的端端口   
struct sockaddr_in  destaddr;       //目的端套接字地址结构
char *hostname;                     //目的端主机名
char sendbuf[BUFSIZE], recvbuf[BUFSIZE];    //发送缓冲区和接收缓冲区
int datalen;
int alarm_flag;                     //闹钟标记

并在main.c中加入如下代码:

extern struct troptions    troptions;
extern uint16_t    sport, dport;           //源端端口和目的端端口   
extern struct sockaddr_in  destaddr;       //目的端套接字地址结构
extern char *hostname;                     //目的端主机名
extern char sendbuf[BUFSIZE], recvbuf[BUFSIZE];    //发送缓冲区和接收缓冲区
extern int datalen;
extern int alarm_flag;                     //闹钟标记
dport = 32768 + 666;

4.

web应用在打开的时候出现乱码现象

image-20250412194551326

是因为页面源码使用的是utf-8编码,使用nodepad++转码为ansi编码之后即可。

image-20250412194656019