原始套接字编程示例

This is a continuation from Part IV series, Advanced TCP/IP Programming Tutorial.  Working program examples if any compiled using gcc, tested using the public IPs, run on Fedora Core 3, with several times of update, as root or SUID 0.  The Fedora machine used for the testing having the "No Stack Execute" disabled and the SELinux set to default configuration.

 

Building and injecting RAW datagrams program examples

[root@bakawali testraw]# cat rawudp.c

// ----rawudp.c------

// Must be run by root lol! Just datagram, no payload/data

#include <unistd.h>

#include <stdio.h>

#include <sys/socket.h>

#include <netinet/ip.h>

#include <netinet/udp.h>

 

// The packet length

#define PCKT_LEN 8192

 

// Can create separate header file (.h) for all headers' structure

// The IP header's structure

struct ipheader {

 unsigned char      iph_ihl:5, iph_ver:4;

 unsigned char      iph_tos;

 unsigned short int iph_len;

 unsigned short int iph_ident;

 unsigned char      iph_flag;

 unsigned short int iph_offset;

 unsigned char      iph_ttl;

 unsigned char      iph_protocol;

 unsigned short int iph_chksum;

 unsigned int       iph_sourceip;

 unsigned int       iph_destip;

};

 

// UDP header's structure

struct udpheader {

 unsigned short int udph_srcport;

 unsigned short int udph_destport;

 unsigned short int udph_len;

 unsigned short int udph_chksum;

};

// total udp header length: 8 bytes (=64 bits)

 

// Function for checksum calculation. From the RFC,

// the checksum algorithm is:

//  "The checksum field is the 16 bit one's complement of the one's

//  complement sum of all 16 bit words in the header.  For purposes of

//  computing the checksum, the value of the checksum field is zero."

unsigned short csum(unsigned short *buf, int nwords)

{       //

        unsigned long sum;

        for(sum=0; nwords>0; nwords--)

                sum += *buf++;

        sum = (sum >> 16) + (sum &0xffff);

        sum += (sum >> 16);

        return (unsigned short)(~sum);

}
 

// Source IP, source port, target IP, target port from the command line arguments

int main(int argc, char *argv[])

{

int sd;

// No data/payload just datagram

char buffer[PCKT_LEN];

// Our own headers' structures

struct ipheader *ip = (struct ipheader *) buffer;

struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));

// Source and destination addresses: IP and port

struct sockaddr_in sin, din;

int one = 1;

const int *val = &one;

 

memset(buffer, 0, PCKT_LEN);

 

if(argc != 5)

{

printf("- Invalid parameters!!!\n");

printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);

exit(-1);

}

 

// Create a raw socket with UDP protocol

sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);

if(sd < 0)

{

perror("socket() error");

// If something wrong just exit

exit(-1);

}

else

printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");

 

// The source is redundant, may be used later if needed

// The address family

sin.sin_family = AF_INET;

din.sin_family = AF_INET;

// Port numbers

sin.sin_port = htons(atoi(argv[2]));

din.sin_port = htons(atoi(argv[4]));

// IP addresses

sin.sin_addr.s_addr = inet_addr(argv[1]);

din.sin_addr.s_addr = inet_addr(argv[3]);

 

// Fabricate the IP header or we can use the

// standard header structures but assign our own values.

ip->iph_ihl = 5;

ip->iph_ver = 4;

ip->iph_tos = 16; // Low delay

ip->iph_len = sizeof(struct ipheader) + sizeof(struct udpheader);

ip->iph_ident = htons(54321);

ip->iph_ttl = 64; // hops

ip->iph_protocol = 17; // UDP

// Source IP address, can use spoofed address here!!!

ip->iph_sourceip = inet_addr(argv[1]);

// The destination IP address

ip->iph_destip = inet_addr(argv[3]);

 

// Fabricate the UDP header. Source port number, redundant

udp->udph_srcport = htons(atoi(argv[2]));

// Destination port number

udp->udph_destport = htons(atoi(argv[4]));

udp->udph_len = htons(sizeof(struct udpheader));

// Calculate the checksum for integrity

ip->iph_chksum = csum((unsigned short *)buffer, sizeof(struct ipheader) + sizeof(struct udpheader));

// Inform the kernel do not fill up the packet structure. we will build our own...

if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)

{

perror("setsockopt() error");

exit(-1);

}

else

printf("setsockopt() is OK.\n");

 

// Send loop, send for every 2 second for 100 count

printf("Trying...\n");

printf("Using raw socket and UDP protocol\n");

printf("Using Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));

 

int count;

for(count = 1; count <=20; count++)

{

if(sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)

// Verify

{

perror("sendto() error");

exit(-1);

}

else

{

printf("Count #%u - sendto() is OK.\n", count);

sleep(2);

}

}

close(sd);

return 0;

}

 

[root@bakawali testraw]# gcc rawudp.c -o rawudp

[root@bakawali testraw]# ./rawudp

- Invalid parameters!!!

- Usage ./rawudp <source hostname/IP> <source port> <target hostname/IP> <target port>

[root@bakawali testraw]# ./rawudp 192.168.10.10 21 203.106.93.91 8080

socket() - Using SOCK_RAW socket and UDP protocol is OK.

setsockopt() is OK.

Trying...

Using raw socket and UDP protocol

Using Source IP: 192.168.10.10 port: 21, Target IP: 203.106.93.91 port: 8080.

Count #1 - sendto() is OK.

Count #2 - sendto() is OK.

Count #3 - sendto() is OK.

Count #4 - sendto() is OK.

Count #5 - sendto() is OK.

Count #6 - sendto() is OK.

Count #7 - sendto() is OK.

...
 

 

You can use network monitoring tools to capture the raw socket datagrams at the target machine to see the effect.  The following is a raw socket and tcp program example.

[root@bakawali testraw]# cat rawtcp.c

//---cat rawtcp.c---

// Run as root or SUID 0, just datagram no data/payload

#include <unistd.h>

#include <stdio.h>

#include <sys/socket.h>

#include <netinet/ip.h>

#include <netinet/tcp.h>

// Packet length

#define PCKT_LEN 8192

 

// May create separate header file (.h) for all

// headers' structures

// IP header's structure

struct ipheader {

 unsigned char      iph_ihl:5, /* Little-endian */

                    iph_ver:4;

 unsigned char      iph_tos;

 unsigned short int iph_len;

 unsigned short int iph_ident;

 unsigned char      iph_flags;

 unsigned short int iph_offset;

 unsigned char      iph_ttl;

 unsigned char      iph_protocol;

 unsigned short int iph_chksum;

 unsigned int       iph_sourceip;

 unsigned int       iph_destip;

};

 

/* Structure of a TCP header */

struct tcpheader {

 unsigned short int tcph_srcport;

 unsigned short int tcph_destport;

 unsigned int       tcph_seqnum;

 unsigned int       tcph_acknum;

 unsigned char      tcph_reserved:4, tcph_offset:4;

 // unsigned char tcph_flags;

  unsigned int

       tcp_res1:4,       /*little-endian*/

       tcph_hlen:4,      /*length of tcp header in 32-bit words*/

       tcph_fin:1,       /*Finish flag "fin"*/

       tcph_syn:1,       /*Synchronize sequence numbers to start a connection*/

       tcph_rst:1,       /*Reset flag */

       tcph_psh:1,       /*Push, sends data to the application*/

       tcph_ack:1,       /*acknowledge*/

       tcph_urg:1,       /*urgent pointer*/

       tcph_res2:2;

 unsigned short int tcph_win;

 unsigned short int tcph_chksum;

 unsigned short int tcph_urgptr;

};

 

// Simple checksum function, may use others such as Cyclic Redundancy Check, CRC

unsigned short csum(unsigned short *buf, int len)

{

        unsigned long sum;

        for(sum=0; len>0; len--)

                sum += *buf++;

        sum = (sum >> 16) + (sum &0xffff);

        sum += (sum >> 16);

        return (unsigned short)(~sum);

}

 

int main(int argc, char *argv[])

{

int sd;

// No data, just datagram

char buffer[PCKT_LEN];

// The size of the headers

struct ipheader *ip = (struct ipheader *) buffer;

struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof(struct ipheader));

struct sockaddr_in sin, din;

int one = 1;

const int *val = &one;

 

memset(buffer, 0, PCKT_LEN);

 

if(argc != 5)

{

printf("- Invalid parameters!!!\n");

printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);

exit(-1);

}

 

sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);

if(sd < 0)

{

   perror("socket() error");

   exit(-1);

}

else

printf("socket()-SOCK_RAW and tcp protocol is OK.\n");

 

// The source is redundant, may be used later if needed

// Address family

sin.sin_family = AF_INET;

din.sin_family = AF_INET;

// Source port, can be any, modify as needed

sin.sin_port = htons(atoi(argv[2]));

din.sin_port = htons(atoi(argv[4]));

// Source IP, can be any, modify as needed

sin.sin_addr.s_addr = inet_addr(argv[1]);

din.sin_addr.s_addr = inet_addr(argv[3]);

// IP structure

ip->iph_ihl = 5;

ip->iph_ver = 4;

ip->iph_tos = 16;

ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);

ip->iph_ident = htons(54321);

ip->iph_offset = 0;

ip->iph_ttl = 64;

ip->iph_protocol = 6; // TCP

ip->iph_chksum = 0; // Done by kernel

 

// Source IP, modify as needed, spoofed, we accept through command line argument

ip->iph_sourceip = inet_addr(argv[1]);

// Destination IP, modify as needed, but here we accept through command line argument

ip->iph_destip = inet_addr(argv[3]);

 

// The TCP structure. The source port, spoofed, we accept through the command line

tcp->tcph_srcport = htons(atoi(argv[2]));

// The destination port, we accept through command line

tcp->tcph_destport = htons(atoi(argv[4]));

tcp->tcph_seqnum = htonl(1);

tcp->tcph_acknum = 0;

tcp->tcph_offset = 5;

tcp->tcph_syn = 1;

tcp->tcph_ack = 0;

tcp->tcph_win = htons(32767);

tcp->tcph_chksum = 0; // Done by kernel

tcp->tcph_urgptr = 0;

// IP checksum calculation

ip->iph_chksum = csum((unsigned short *) buffer, (sizeof(struct ipheader) + sizeof(struct tcpheader)));

 

// Inform the kernel do not fill up the headers' structure, we fabricated our own

if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)

{

    perror("setsockopt() error");

    exit(-1);

}

else

   printf("setsockopt() is OK\n");

 

printf("Using:::::Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));

 

// sendto() loop, send every 2 second for 50 counts

unsigned int count;

for(count = 0; count < 20; count++)

{

if(sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)

// Verify

{

   perror("sendto() error");

   exit(-1);

}

else

   printf("Count #%u - sendto() is OK\n", count);

sleep(2);

}

close(sd);

return 0;

}

 

[root@bakawali testraw]# gcc rawtcp.c -o rawtcp

[root@bakawali testraw]# ./rawtcp

- Invalid parameters!!!

- Usage: ./rawtcp <source hostname/IP> <source port> <target hostname/IP> <target port>

[root@bakawali testraw]# ./rawtcp 10.10.10.100 23 203.106.93.88 8008

socket()-SOCK_RAW and tcp protocol is OK.

setsockopt() is OK

Using:::::Source IP: 10.10.10.100 port: 23, Target IP: 203.106.93.88 port: 8008.

Count #0 - sendto() is OK

Count #1 - sendto() is OK

Count #2 - sendto() is OK

Count #3 - sendto() is OK

Count #4 - sendto() is OK

...

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
博客地址:https://blog.csdn.net/weixin_41749063/article/details/104023987 摘要: ## 1.简介 其实Qt网络模块中自带的[QTcpsocket](https://doc.qt.io/archives/qt-5.6/qtcpsocket.html)已经封装的很好了,避免了用原始编程繁琐的过程,不过大部分应用场景我们希望将收发数据 运行在一个单独的线程,不阻塞界面或其他线程。所以结合Qt自带的QThread类 简单的封装了一下QTcpsocket,使其工作 在单独线程,并加入了心跳和断线重连机制。 ## 2.EasyClient类说明 由于触QT时间不是很长,所以写的不是很好,可能里边也有Bug,不过觉得这个思路应该是可行的。封装的比较简单,若有问题完全可以自己改改。主要提供一个思路就是的将一个继承自QObject的子类转移到一个线程,使其在这个线程里进行事件循环,开一个定时器用于发送心跳和重连。 经过采坑发现,定时器的开和关需放在实例化EasyClient子类的那个线程(下面称之为主线程),不能在事件循环线程中(下面称之为子线程中)否则会有错。实例化QTcpsock需要在 子线程中进行,否则会出现无法正常通信的现象。 使用时只需要实例化一个EasyClient的子类,重写SendHeartBeat()和DisPoseReceiveData()两个纯虚函数,SendHeartBeat()决定发什么内容作为心跳指令,当有数据可读时会全部读入,只需要在DisPoseReceiveData()做处理即可。.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值