如何给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

分析结果无误:

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值