1 重新搭建实验环境

前面都是用实验楼环境做的实验,偷的懒总是要还的,这一次重装环境前后花了十几个小时,踩了无数的坑。

1.1 Ubuntu和LINUX内核的区别

Ubuntu是基于LINUX内核编写的一个操作系统。LINUX内核定义了一些基本的系统功能,Ubuntu在内核之上加入了图形界面,包管理等功能,优化了人机交互。本次实验,要求使用LINUX内核5.0以上,所以,在下载安装完Ubuntu系统后,需要对内核进行更新。

$ uname -a

上面这个指令会显示Ubuntu当前的内核版本,我们可以通过它来观察内核的升级是否成功。

1.2 从零开始

下载安装Ubuntu

首先到Ubuntu官网上下载一个Ubuntu镜像,但是太慢了,我们可以在国内的镜像网站上去下载。指路

反汇编init

init进行反汇编

$ objdump -d init > init_ASM.txt

查看init_ASM.txt文件,在第104553行找到socket对应的系统调用。

证明对于socket api的调用是通过socketcall这个特殊中断来实现的。

syscall的具体实现

利用同样的办法,我们按照上一节的方法启动qemu进行远程调试,设置如下断点:

$ (gdb) break sys_socketcall

跟踪到一个关键函数:SYSCALL_DEFINE2(),它位于linux-5.0.1/net/socket.c之中。
关键代码如下:

switch (call) {     case SYS_SOCKET:         err = __sys_socket(a0, a1, a[2]);         break;     case SYS_BIND:         err = __sys_bind(a0, (struct sockaddr __user *)a1, a[2]);         break;     case SYS_CONNECT:         err = __sys_connect(a0, (struct sockaddr __user *)a1, a[2]);         break;     case SYS_LISTEN:         err = __sys_listen(a0, a1);         break;     case SYS_ACCEPT:         err = __sys_accept4(a0, (struct sockaddr __user *)a1,                     (int __user *)a[2], 0);         break;     // ... 省略其余部分     }

可见,每次socket都会调用同一个函数,通过传入的call值不同,在分支语句中执行对应的系统服务例程。

2.2 Socket封装网络协议的多态机制

__sys_socket()为例,其源码位于同一文件下,也是C语言实现的:

int __sys_socket(int family, int type, int protocol) {     int retval;     struct socket *sock;     int flags;      /* Check the SOCK_* constants for consistency.  */     BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC);     BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK);     BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK);     BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK);      flags = type & ~SOCK_TYPE_MASK;     if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))