如何给UNIX域Socket套接字抓包?

Posted rtoax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何给UNIX域Socket套接字抓包?相关的知识,希望对你有一定的参考价值。

目录

源代码

client.c

common.c  

common.h  

Makefile  

server.c  

undump.sh

测试


源代码

https://github.com/Rtoax/test/tree/master/ipc/socket/unsocket-pcap


client.c

#include "common.h"

void main()

    int connect_fd;
    int ret = 0, len;

    connect_fd  = unsocket_client(UNIX_DOMAIN);
    int val = 1;
	setsockopt(connect_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
    printf("fd: %d\\n", connect_fd);
	while(1)
	
		scanf("%s", buf);
        
		ret = write(connect_fd, buf, strlen(buf)); 
		printf("send bytes = %d: %s\\n", ret, buf);
	

    len = read(connect_fd, buf, MSG_LENGTH);
    
    printf("%d:%s\\n", len, buf);
    
    close(connect_fd);


common.c  

#include "common.h"

char buf[MSG_LENGTH];

int unsocket_server(const char *PATH)

    struct sockaddr_un srv_addr;
    
    int listen_fd, ret;
    
    listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    
    if(listen_fd < 0)
    
        return -1;
    
    else
    
        srv_addr.sun_family = AF_UNIX;
        strncpy(srv_addr.sun_path, PATH, sizeof(srv_addr.sun_path)-1);
        
        unlink(PATH);
        
        ret = bind(listen_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
        
        if(ret == -1)
        
            close(listen_fd);
            unlink(PATH);
            return -1;
        
        
        ret = listen(listen_fd, 1);
        if(ret == -1)
        
            close(listen_fd);
            unlink(PATH);
            return -1;
        
        
        chmod(PATH, 00777);
    
    return listen_fd;


int unsocket_client(const char *PATH)

    int connect_fd;
    int ret = 0;
    
    static struct sockaddr_un srv_addr;
    
    connect_fd = socket(AF_UNIX, SOCK_STREAM, 0);
    
    if(connect_fd < 0)
    
        return -1;
    
    else
    
        srv_addr.sun_family = AF_UNIX;
        strcpy(srv_addr.sun_path, UNIX_DOMAIN);
        
        ret = connect(connect_fd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
        
        if(ret == -1)
        
            close(connect_fd);
            return -1;
        
    
    
    return connect_fd;


common.h  


#ifndef _COMMON_H
#define _COMMON_H

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/tcp.h>
#include <sys/mman.h>

#define UNIX_DOMAIN "./rtoax_unsocket_pcap"

#define MSG_LENGTH          1024

#define MAX_CLIENT_NUM      10

#define debug() printf("%s:%d\\n", __func__, __LINE__)

extern char                 buf[MSG_LENGTH];

int unsocket_server(const char *PATH);
int unsocket_client(const char *PATH);

#endif /*<_COMMON_H>*/

Makefile  

ALL:
	gcc server.c common.c -o server -lm
	gcc client.c common.c -o client -lm

clean:
	rm -f server client *.pcap

server.c  


#include "common.h"

int listen_fd;

void sig_handler(int signum)

    printf("------------------------------------------------\\n");
    close(listen_fd);
    exit(1);



void main()

    int com_fd; 
    int ret = 0;
    int i;
    int len;
    struct sockaddr_un clt_addr;

    signal(SIGINT, sig_handler);
    
    listen_fd = unsocket_server(UNIX_DOMAIN);
    printf("------------------------------------------------\\n");
    printf("-- UNIX Server %s\\n", UNIX_DOMAIN);
    while(1)
    
        len = sizeof(clt_addr);
        com_fd = accept(listen_fd, (struct sockaddr*)&clt_addr, &len);

		int val = 1;
		setsockopt(listen_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
		setsockopt(com_fd, SOL_TCP, TCP_NODELAY, &val, sizeof(val));
        if(com_fd < 0)
        
            perror("cannot accept client connect request.");
            close(listen_fd);
            unlink(UNIX_DOMAIN);
            break;
        
        
        memset(buf, 0, MSG_LENGTH);

		while(1)
		
			len = read(com_fd, buf, MSG_LENGTH);
			printf("-- len= %d, recv: %s\\n", len, buf);
			memset(buf, 0, MSG_LENGTH);
			if(len<=0)
				break;
		

        buf[0] = 'X';
        
        write(com_fd, buf, MSG_LENGTH);
        
        close(com_fd);
    

undump.sh

#!/bin/bash

################################################################################
#
#   UNIX域Socket抓包
#   
#   作者:RToax
#   时间:2020年11月9日
#
################################################################################

exe_name=$0
eth_port="lo"

#UNIX socket 文件路径
unix_path=/tmp/unix.sock
unix_path_original="$unix_path.original"
ARG_UNIX_PATH="-u"
ARG_UNIX_PATH_S="UNIX socket path name."

#抓包文件
pcap_switch=0
pcap_file=pcap.pcap
ARG_PCAP_FILE="-f"
ARG_PCAP_FILE_S="Pcap File Name. default $pcap_file, no set no save."

#临时端口
tcp_port=8087
ARG_TCP_PORT="-p"
ARG_TCP_PORT_S="TMP port for swap UNIX socket. default $tcp_port"

#显示包的比特信息,如下:
# 0x0000:  4500 0034 52ae 4000 4006 ea13 7f00 0001
# 0x0010:  7f00 0001 c82a 07cf 6a88 73d9 bfa9 666c
# 0x0020:  8010 01f8 fe28 0000 0101 080a a2d6 9545
# 0x0030:  a2d6 9545
pbits_flag=0
ARG_PBITS_DETAIL="-x"
ARG_PBITS_DETAIL_S="Show Packet Bits."

#帮助信息
ARG_USAGE="-h"
ARG_USAGE_S="Show usage."

#tcpdump的参数
ARG_TCPDUMP=" -i $eth_port -netvvv -N -q "

function usage()

    printf "\\n"
    printf "$exe_name [option] [value]\\n"
    printf "\\n"
    printf "    $ARG_UNIX_PATH   $ARG_UNIX_PATH_S \\n"
    printf "    $ARG_PCAP_FILE   $ARG_PCAP_FILE_S\\n"
    printf "    $ARG_TCP_PORT   $ARG_TCP_PORT_S\\n"
    printf "    $ARG_PBITS_DETAIL   $ARG_PBITS_DETAIL_S\\n"
    printf "    $ARG_USAGE   $ARG_USAGE_S\\n"


function parse_args()

    argvs=($(echo "$@"))
    elements=$[ $# - 1 ]
    for (( i = 0; i <= $elements; i++ ))
    
        # 解析抓包文件参数
        if [ $argvs[$i] = $ARG_USAGE ]; then
            usage
            return 1
        fi
        # 解析UNIXsocket路径参数
        if [ $argvs[$i] = $ARG_UNIX_PATH ]; then
            unix_path=$argvs[$i+1]
            #文件必须存在
            if [ ! -e $unix_path ]; then 
                printf "Unix Path not exist. $unix_path\\n"
                printf "TYPE>> $exe_name $ARG_USAGE for help.\\n"
                return 1
            fi
            #文件必须为Socket类型
            if [ ! -S $unix_path ]; then 
                printf "File must be Unix Socket Path. $unix_path\\n"
                printf "TYPE>> $exe_name $ARG_USAGE for help.\\n"
                return 1
            fi
            
        fi
        # 解析抓包文件参数
        if [ $argvs[$i] = $ARG_PCAP_FILE ]; then
            pcap_file=$argvs[$i+1]
            pcap_switch=1
            if [ -e $pcap_file ]; then 
                printf "PCAP file: $pcap_file exist, overwrite it.\\n"
                printf "TYPE>> $exe_name $ARG_USAGE for help.\\n"
                rm -f $pcap_file
            fi
        fi
        
        # 显示包的比特信息
        if [ $argvs[$i] = $ARG_PBITS_DETAIL ]; then
            pbits_flag=1
        fi
        # 解析临时端口参数
        if [ $argvs[$i] = $ARG_TCP_PORT ]; then
            tcp_port=$argvs[$i+1]
        fi
        
    
    return 0


if [ ! -e  /usr/bin/socat ]; then 
    printf "Not socat found, install socat first.\\n"
    exit 0
fi 
if [ ! -e  /usr/sbin/tcpdump ]; then 
    printf "Not tcpdump found, install tcpdump first.\\n"
    exit 0
fi 

#没有参数直接退出
if [ $# -lt 1 ]; then 
    usage
    exit 0
fi

#解析参数
parse_args $*

#参数解析失败,直接退出
if [ $? -ne 0 ]; then 
    exit 0
fi


unix_path_original="$unix_path.original"


# Move socket files
mv "$unix_path" "$unix_path_original"
trap " rm '$unix_path'; mv '$unix_path_original' '$unix_path'; " EXIT

#创建一个TCP监听,一个UNIXSocket监听
socat -t100 "TCP-LISTEN:$tcp_port,reuseaddr,fork" "UNIX-CONNECT:$unix_path_original" &

#创建一个UNIX监听和一个TCP监听
socat -t100 "UNIX-LISTEN:$unix_path,mode=777,reuseaddr,fork" "TCP:localhost:$tcp_port" &

#ARG_TCPDUMP=" -i $eth_port -netvvv "
#端口过滤
ARG_TCPDUMP=$ARG_TCPDUMP" port $tcp_port "

#是否输出抓包文件
if [ $pcap_switch = "1" ]; then
    ARG_TCPDUMP=$ARG_TCPDUMP" -w $pcap_file"
fi

if [ $pbits_flag = "1" ]; then
    ARG_TCPDUMP=$ARG_TCPDUMP" -x"
fi


#保存抓包数据  -i lo -netvvv -x port $tcpport -w "$pcapfile"
tcpdump $ARG_TCPDUMP

 

测试

# ./undump.sh 

./undump.sh [option] [value]

    -u   UNIX socket path name. 
    -f   Pcap File Name. default pcap.pcap, no set no save.
    -p   TMP port for swap UNIX socket. default 8087
    -x   Show Packet Bits.
    -h   Show usage.

启动服务端程序,之后,启动抓包脚本:

# ./server
------------------------------------------------
-- UNIX Server ./rtoax_unsocket_pcap

启动脚本:

# ./undump.sh 

./undump.sh [option] [value]

    -u   UNIX socket path name. 
    -f   Pcap File Name. default pcap.pcap, no set no save.
    -p   TMP port for swap UNIX socket. default 8087
    -x   Show Packet Bits.
    -h   Show usage.

# ./undump.sh -u rtoax_unsocket_pcap -x
2020/11/09 15:46:03 socat[60255] E bind(5, AF=2 0.0.0.0:8087, 16): Address already in use
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

启动客户端:

# ./client
fd: 3

此时,抓包脚本启动的中断下将如下打印:

(多次测试时,会出现“Address already in use”问题,使用-p参数修改端口即可)。

# ./undump.sh -u rtoax_unsocket_pcap -x
2020/11/09 15:46:03 socat[60255] E bind(5, AF=2 0.0.0.0:8087, 16): Address already in use
tcpdump: listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
00:00:00:00:00:00 > 00:00:00:00:00:00, IPv4, length 74: (tos 0x0, ttl 64, id 53323, offset 0, flags [DF], proto TCP (6), length 60)
    127.0.0.1.49498 > 127.0.0.1.simplifymedia: tcp 0
	0x0000:  4500 003c d04b 4000 4006 6c6e 7f00 0001
	0x0010:  7f00 0001 c15a 1f97 6d73 6e4d 0000 0000
	0x0020:  a002 ffd7 fe30 0000 0204 ffd7 0402 080a
	0x0030:  a2fe cf12 0000 0000 0103 0307
00:00:00:00:00:00 > 00:00:00:00:00:00, IPv4, length 74: (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    127.0.0.1.simplifymedia > 127.0.0.1.49498: tcp 0
	0x0000:  4500 003c 0000 4000 4006 3cba 7f00 0001
	0x0010:  7f00 0001 1f97 c15a 7fd1 b2c6 6d73 6e4e
	0x0020:  a012 ffcb fe30 0000 0204 ffd7 0402 080a
	0x0030:  a2fe cf12 a2fe cf12 0103 0307
00:00:00:00:00:00 > 00:00:00:00:00:00, IPv4, length 66: (tos 0x0, ttl 64, id 53324, offset 0, flags [DF], proto TCP (6), length 52)
    127.0.0.1.49498 > 127.0.0.1.simplifymedia: tcp 0
	0x0000:  4500 0034 d04c 4000 4006 6c75 7f00 0001
	0x0010:  7f00 0001 c15a 1f97 6d73 6e4e 7fd1 b2c7
	0x0020:  8010 0200 fe28 0000 0101 080a a2fe cf13
	0x0030:  a2fe cf12

在客户端发包,服务端接收:

# ./client
fd: 3
aaaaaaaaaaaaaaaaaaaaaaaaaaaa
send bytes = 28: aaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbb
send bytes = 25: bbbbbbbbbbbbbbbbbbbbbbbbb

抓包工具有如下打印:

00:00:00:00:00:00 > 00:00:00:00:00:00, IPv4, length 94: (tos 0x0, ttl 64, id 53325, offset 0, flags [DF], proto TCP (6), length 80)
    127.0.0.1.49498 > 127.0.0.1.simplifymedia: tcp 28
	0x0000:  4500 0050 d04d 4000 4006 6c58 7f00 0001
	0x0010:  7f00 0001 c15a 1f97 6d73 6e4e 7fd1 b2c7
	0x0020:  8018 0200 fe44 0000 0101 080a a300 6e8e
	0x0030:  a2fe cf12 6161 6161 6161 6161 6161 6161
	0x0040:  6161 6161 6161 6161 6161 6161 6161 6161
00:00:00:00:00:00 > 00:00:00:00:00:00, IPv4, length 66: (tos 0x0, ttl 64, id 62517, offset 0, flags [DF], proto TCP (6), length 52)
    127.0.0.1.simplifymedia > 127.0.0.1.49498: tcp 0
	0x0000:  4500 0034 f435 4000 4006 488c 7f00 0001
	0x0010:  7f00 0001 1f97 c15a 7fd1 b2c7 6d73 6e6a
	0x0020:  8010 0200 fe28 0000 0101 080a a300 6e8e
	0x0030:  a300 6e8e
00:00:00:00:00:00 > 00:00:00:00:00:00, IPv4, length 91: (tos 0x0, ttl 64, id 53326, offset 0, flags [DF], proto TCP (6), length 77)
    127.0.0.1.49498 > 127.0.0.1.simplifymedia: tcp 25
	0x0000:  4500 004d d04e 4000 4006 6c5a 7f00 0001
	0x0010:  7f00 0001 c15a 1f97 6d73 6e6a 7fd1 b2c7
	0x0020:  8018 0200 fe41 0000 0101 080a a300 8116
	0x0030:  a300 6e8e 6262 6262 6262 6262 6262 6262
	0x0040:  6262 6262 6262 6262 6262 6262 62
00:00:00:00:00:00 > 00:00:00:00:00:00, IPv4, length 66: (tos 0x0, ttl 64, id 62518, offset 0, flags [DF], proto TCP (6), length 52)
    127.0.0.1.simplifymedia > 127.0.0.1.49498: tcp 0
	0x0000:  4500 0034 f436 4000 4006 488b 7f00 0001
	0x0010:  7f00 0001 1f97 c15a 7fd1 b2c7 6d73 6e83
	0x0020:  8010 0200 fe28 0000 0101 080a a300 8116
	0x0030:  a300 8116

分析结果无误:

 

 

以上是关于如何给UNIX域Socket套接字抓包?的主要内容,如果未能解决你的问题,请参考以下文章

Unix域套接字-Unix Domain Socket(转)

C++ 使用 send_to 提升 unix 域套接字

可以在Unix域套接字上使用SO_REUSEPORT吗?

如何通过 unix socket 设置 Apache2 和 PHP-FPM?

《Unix 网络编程》15:Unix 域协议

Unix域套接字简介