RowSocket mac

Posted 小米渣的逆袭

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RowSocket mac相关的知识,希望对你有一定的参考价值。

#ifndef __TCPROWSOCKET_H__
#define __TCPROWSOCKET_H__

#include <stdio.h>    //for printf
#include <string.h> //memset
#include <sys/socket.h>    //for socket ofcourse
#include <stdlib.h> //for exit(0);
#include <errno.h> //For errno - the error number
#include <netinet/tcp.h>    //Provides declarations for tcp header
#include <netinet/ip.h>    //Provides declarations for ip header
#include <arpa/inet.h> // inet_addr
#include <unistd.h> // sleep()
#include <netinet/in.h>
#include <stdbool.h>

#pragma pack(1)

#define LITTLE_ENDIAN_BITFIELD 1

/*	IP协议头 参考文章
*	https://www.cnblogs.com/yyxianren/p/10790730.html
*	https://blog.csdn.net/weixin_44678969/article/details/105496550
*/

//IP协议头结构体,标准协议应该是20字节 整个结构体是21字节version+headerLen占用了2字节
struct IPHeader

#if defined(LITTLE_ENDIAN_BITFIELD)
    //首部长度        4bit
    unsigned char headerLen : 4;
    //版本号        4bit
    unsigned char version : 4;   
#elif defined (BIG_ENDIAN_BITFIELD)
    //版本号        4bit
    unsigned char version : 4;
    //首部长度        4bit
    unsigned char headerLen : 4;
#endif
	//服务类型		1字节
	unsigned char tos;
	//总长度		2字节
	unsigned short totalLen;
	//标识			2字节
	unsigned short id;
	//位标志+片偏移	3bit + 13bit
	unsigned short flagOffset;
	//生存时间		1字节
	unsigned char ttl;
	//协议			1字节
	unsigned char protocol;
	//首部检验和    2字节
	unsigned short checksum;
	//源IP地址		4字节
	unsigned int srcIP;
	//目的IP地址	4字节
	unsigned int dstIP;
;

//TCP协议相关文章 //https://blog.csdn.net/wangyiyungw/article/details/82178070
//				  //https://blog.csdn.net/u014530704/article/details/78842000

//TCP协议头结构体,标准协议应该是20字节
struct TCPHeader

	//源端口	   2字节
	unsigned short srcPort;
	//目的端口	   2字节
	unsigned short dstPort;

	//序列号	Sequence Number 4字节
	//封包序号 如果 TCP 数据太大时(大于 IP 封包的容许程度), 就得要进行分段.这个 Sequence Number 就是记录每个封包的序号,
	//可以让收受端重新将 TCP 的数据组合起来。序号字段的值则指的是本报文段所发送的数据的第一个字节的序号
	//确认号 为了确认主机端确实有收到我们 client 端所送出的封包数据,我们 client 端当然希望能够收到主机方面的响应,那就是这个 Acknowledge Number 的用途了
	//当 client 端收到这个确认码时,就能够确定之前传递的封包已经被正确的收下了.这个号是期望收到对方的下一个报文段的数据的第一个字节的序号
	unsigned int seqNum;
	//确认序列号 Acknowledgment Number 4字节
	unsigned int ackNum;
#if defined(LITTLE_ENDIAN_BITFIELD)
    //4位首部长度    4bit
    unsigned char reserved1 : 4;
    //保留6位        6bit
    unsigned char reserved2 : 4;
    //flags
    // 用来释放一个连接。当FIN=1时表示要求释放连接。 1      1bit
    unsigned char fin : 1;
    //同步当SYN=1时,表示这是一个连接请求或连接接受报文。 1bit
    unsigned char syn : 1;
    //复位,当TCP连接中出现了严重差错,必须释放连接。     1bit
    unsigned char rst : 1;
    //当两个应用程序进行通信时,当PSH=1时,表示尽快地用“推送”给应用程序,而不用等到缓冲区满了再向上交付。 1bit
    unsigned char psh : 1;
    //当ACK=1时,确认字段有效,在连接建立后的所有报文段都必须把ACK置为1。   1bit
    unsigned char ack : 1;
    紧急指针,当URG=1时,表示紧急指针有效,应该尽快传送。用来处理避免TCP数据流中断  1bit
    unsigned char urg : 1;
    unsigned char ece : 1;
    unsigned char cwr : 1;
#else
    //保留6位        6bit
    unsigned char reserved2 : 4;
    //4位首部长度    4bit
    unsigned char reserved1 : 4;
    unsigned char cwr : 1;
    unsigned char ece : 1;
    unsigned char urg : 1;
    unsigned char ack : 1;
    unsigned char psh : 1;
    unsigned char rst : 1;
    unsigned char syn : 1;
    unsigned char fin : 1;
#endif
	
    
	//16位窗口大小	   2字节
	unsigned short windownSize;
	//16位TCP检验和    2字节
	unsigned short checksum;
	//16位紧急指针当URG=1时.表示紧急指针有效.应该尽快传送,不要按本来的列队次序传送  2字节
	unsigned short urgPtr;
;

//TCP伪首部
struct PseudoHeader

	//源地址
	unsigned int srcIP;
	//目的地址
	unsigned int dstIP;
	//置空,用于填充对齐
	unsigned char mustBeZero;
	//协议类型
	unsigned char protocol;
	//TCP长度
	unsigned short len;
;


struct MSSOption

	unsigned char kind;
	unsigned char length;
	unsigned short maxValue;
;
struct SACKOption

	unsigned char kind;
	unsigned char length;
;
struct TimestampsOption

	unsigned char kind;
	unsigned char length;
	unsigned int timestamp;
	unsigned int timestampReply;
;
struct NoOperation

	unsigned char type;
;
struct WindowScaleOption

	unsigned char kind;
	unsigned char length;
	unsigned char shiftCount;
;

int sendTcp(int sockfd, struct sockaddr_in* srcAddr, struct sockaddr_in* dstAddr, char syn, char ack, bool addMssOption, bool addSACKOption, bool addTsOption, bool addNoOption, bool addWindowScale);
void parseSynAck(int sockfd, struct sockaddr_in* dstAddr);

void test2 (void);
#pragma pack()
#endif
#include "TcpRowSocket.h"

int g_tcpSeqNum = 111;
int g_tcpAckNum = 0;
//ip数字转字符串
void ipLLToStr(long long ip_num,char* ip_str)

	unsigned int iptok1 = (ip_num & 0xFF000000) >> 24;
	unsigned int iptok2 = (ip_num & 0x00FF0000) >> 16;
	unsigned int iptok3 = (ip_num & 0x0000FF00) >> 8;
	unsigned int iptok4 = ip_num & 0x000000FF;
	char ip[32];
	memset(ip, 0, 32);
	snprintf(ip, sizeof(ip), "%d.%d.%d.%d", iptok1, iptok2, iptok3, iptok4);
	strcpy(ip_str,ip);

//打印ip头
void printIPHeader(struct IPHeader* ipHeader)

	char srcIPStr[64] = "", dstIPStr[64] = "";
	ipLLToStr(ntohl(ipHeader->srcIP), srcIPStr);
	ipLLToStr(ntohl(ipHeader->dstIP), dstIPStr);
	int totalLen = ntohs(ipHeader->totalLen);
	char ipHeaderStr[256] = "";
	snprintf(ipHeaderStr, sizeof(ipHeaderStr), "ip header: version:%d,tos:%d,protocol:%d,ttl:%d,srcIP:%s,dstIP:%s,totalLen:%d", ipHeader->version, ipHeader->tos, ipHeader->protocol, ipHeader->ttl, srcIPStr, dstIPStr, totalLen);
	

//打印tcp头
void printTCPHeader(struct TCPHeader* tcpHeader)

//	char tcpHeaderStr[256] = "";
//	snprintf(tcpHeaderStr, sizeof(tcpHeaderStr), "tcp header:srcPort:%d,dstPort:%d,seqNum:%u,ackNum:%u,headerLen:%d,fin:%d,syn:%d,rst:%d" ",psh:%d,ack:%d,urg:%d,windowsSize:%d,checksum:%d,urgPtr:%d", ntohs(tcpHeader->srcPort), ntohs(tcpHeader->dstPort), ntohl(tcpHeader->seqNum), ntohl(tcpHeader->ackNum), tcpHeader->headerLen << 2, tcpHeader->fin, tcpHeader->syn, tcpHeader->rst, tcpHeader->psh, tcpHeader->ack, tcpHeader->urg, ntohs(tcpHeader->windownSize), ntohs(tcpHeader->checksum), tcpHeader->urgPtr);
	

//构造IP头
void buildIPHeader(struct IPHeader* ipHeader,int totalLen,int srcIPNum,int dstIPNum)

	ipHeader->headerLen = sizeof(struct IPHeader) >> 2;
	ipHeader->version = 4;
	//服务类型    ipHeader->tos = 0;
	ipHeader->totalLen = htons(totalLen);
	ipHeader->id = htons(0);
	//设置flag标记为0
	ipHeader->flagOffset = htons(0x02 << 13);
	//运用的协议为TCP协议
	ipHeader->protocol = IPPROTO_TCP;
	//一个封包在网络上可以存活的时间
	ipHeader->ttl = 64;
	ipHeader->srcIP = srcIPNum;
	ipHeader->dstIP = dstIPNum;

//tcp和udp的校验和算法是相同的
unsigned short calChecksum(unsigned short* buffer, int size)

	unsigned long cksum = 0;
	while (size > 1)
	
		cksum += *buffer++;
		size -= sizeof(unsigned short);
	
	if (size)
	
		cksum += *(unsigned char*)buffer;
	
	cksum = (cksum >> 16) + (cksum & 0xffff);
	//将高16bit与低16bit相加
	cksum += (cksum >> 16);
	//将进位到高位的16bit与低16bit 再相加
	return (unsigned short)(~cksum);

//构造tcp协议头
void buildTCPHeader(struct TCPHeader* tcpHeader, struct sockaddr_in* srcAddr, struct sockaddr_in* dstAddr, struct IPHeader* ipHeader, int headerLen, int seqNum, int ackNum, char syn, char ack)

	tcpHeader->srcPort = srcAddr->sin_port;
	tcpHeader->dstPort = dstAddr->sin_port;
	tcpHeader->seqNum = htonl(seqNum);
	tcpHeader->ackNum = htonl(ackNum);
	tcpHeader->urg = 0;
	tcpHeader->ack = ack;
	tcpHeader->psh = 0;
	tcpHeader->rst = 0;
	tcpHeader->syn = syn;
	tcpHeader->fin = 0;
	tcpHeader->windownSize = htons(14600);
	tcpHeader->checksum = 0;
	tcpHeader->urgPtr = 0;
	//tcpHeader->headerLen = headerLen >> 2;
	//根据伪首部的buf计算ip头的校验和
	char psdHeaderBuf[256] = "";
    struct PseudoHeader* psdHeader = (struct PseudoHeader*)psdHeaderBuf;
	psdHeader->srcIP = ipHeader->srcIP;
	psdHeader->dstIP = ipHeader->dstIP;
	psdHeader->mustBeZero = 0;
	psdHeader->protocol = ipHeader->protocol;
	psdHeader->len = htons(sizeof(struct TCPHeader));
	memcpy(psdHeaderBuf + sizeof(struct PseudoHeader), tcpHeader, sizeof(struct TCPHeader));
	tcpHeader->checksum = calChecksum((unsigned short*)psdHeaderBuf, sizeof(struct PseudoHeader) + sizeof(struct TCPHeader));

//发送syn
int sendTcp(int sockfd, struct sockaddr_in* srcAddr, struct sockaddr_in* dstAddr, char syn, char ack, bool addMssOption, bool addSACKOption, bool addTsOption, bool addNoOption, bool addWindowScale)

	char buf[1024] = "";
	int totalLen = sizeof(struct IPHeader) + sizeof(struct TCPHeader);
	if (addMssOption)
	
		totalLen += sizeof(struct MSSOption);
	
	if (addSACKOption)
	
		totalLen += sizeof(struct SACKOption);
	
	if (addTsOption)
	
		totalLen += sizeof(struct TimestampsOption);
	
	if (addNoOption)
	
		totalLen += sizeof(struct NoOperation);
	
	if (addWindowScale)
	
		totalLen += sizeof(struct WindowScaleOption);
	
	int pos = 0;
    struct IPHeader* ipHeader = (struct IPHeader*)buf;
	buildIPHeader(ipHeader, totalLen, srcAddr->sin_addr.s_addr, dstAddr->sin_addr.s_addr);
	printIPHeader(ipHeader);
	pos += sizeof(struct IPHeader);
    struct TCPHeader* tcpHeader = (struct TCPHeader*)(buf + pos);
	buildTCPHeader(tcpHeader, srcAddr, dstAddr, ipHeader, totalLen - sizeof(struct IPHeader), g_tcpSeqNum++, g_tcpAckNum, syn, ack);
	printTCPHeader(tcpHeader);
	pos += sizeof(struct TCPHeader);
	if (addMssOption)
	
        struct MSSOption* mssOption = (struct MSSOption*)(buf + pos);
		mssOption->kind = 2;
		//htons(2);
		mssOption->length = sizeof(struct MSSOption);
		//htons(4);
		mssOption->maxValue = htons(1460);
		pos += sizeof(struct MSSOption);
	
	if (addSACKOption)
	
        struct SACKOption* sackOption = (struct SACKOption*)(buf + pos);
		sackOption->kind = 4;
		sackOption->length = sizeof(struct SACKOption);
		pos += sizeof(struct SACKOption);
	
	if (addTsOption)
	
        struct TimestampsOption* tsOption = (struct TimestampsOption*)(buf + pos);
		tsOption->kind = 8;
		tsOption->length = sizeof(struct TimestampsOption);
		tsOption->timestamp = htonl(111);
		tsOption->timestampReply = 0;
		pos += sizeof(struct TimestampsOption);
	
	if (addNoOption)
	
        struct NoOperation* noOption = (struct NoOperation*)(buf + pos);
		noOption->type = 1;
		pos += sizeof(struct NoOperation);
	
	if (addWindowScale)
	
        struct WindowScaleOption* windowScaleOption = (struct WindowScaleOption*)(buf + pos);
		windowScaleOption->kind = 3;
		windowScaleOption->length = sizeof(struct WindowScaleOption);
		windowScaleOption->shiftCount = 6;
	
	if (sendto(sockfd, buf, totalLen, 0, (struct sockaddr *)dstAddr, sizeof(*dstAddr)) < 0)
	
		perror("sendto error");
	
	return 0;

//解析syn+ack
void parseSynAck(int sockfd, struct sockaddr_in* dstAddr)

	char recvBuf[1024] = "";
	socklen_t cliLen = sizeof(dstAddr);
	int recvLen = recvfrom(sockfd, recvBuf, sizeof(recvBuf), 0, (struct sockaddr*)&dstAddr, &cliLen);
	if (recvLen <= 0)
	
		//cout << "parse syc ack fail,recvLen:" << recvLen << endl;
		return;
	
	int pos = 0;
    struct IPHeader* ipHeader = (struct IPHeader*)recvBuf;
	pos += sizeof(struct IPHeader);
	printIPHeader(ipHeader);
    struct TCPHeader* tcpHeader = (struct TCPHeader*)(recvBuf + pos);
	printTCPHeader(tcpHeader);
	g_tcpSeqNum = ntohl(tcpHeader->ackNum);


unsigned short checksum(unsigned short *ptr,int nbytes)

    register long sum;
    unsigned short oddbyte;
    register short answer;

    sum=0;
    while(nbytes>1) 
        sum+=*ptr++;
        nbytes-=2;
    
    if(nbytes==1) 
        oddbyte=0;
        *((u_char*)&oddbyte)=*(u_char*)ptr;
        sum+=oddbyte;
    

    sum = (sum>>16)+(sum & 0xffff);
    sum = sum + (sum>>16);
    answer=(short)~sum;
    
    return(answer);


void test2 (void)

    //创建一个row socket
    int sockfd = socket(AF_INET, SOCK_RAW, 0);
    if (sockfd < 0)
    
        printf("socket error");
        return;
    
    
    //IPPROTO_TP说明用户自己填写IP报文
    //IP_HDRINCL表示由内核来计算IP报文的头部校验和,和填充那个IP的id
    int one = 1;
    const int *val = &one;
    setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, val, sizeof (one));
    
    //填写数据
    char srcStr[32] = "172.16.60.238";
    char dstStr[32] = "172.16.30.20";
    int srcPort = 1234;
    int dstPort = 5555;
    char* data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int dataLen = (int)strlen(data);
    //4是 opiton4个字节
    unsigned short size = (int)sizeof(struct IPHeader) + (int)sizeof(struct TCPHeader) + 4  + dataLen;
    
    //创建buf区域
    char* buf = (char*)malloc(size);
    memset(buf, 0, size);
    
    //填写option
    char* pOption = buf + sizeof(struct IPHeader) + sizeof(struct TCPHeader);
    pOption[0] = 0x6d;
    pOption[1] = 0x6e;
    pOption[2] = 0x6f;
    pOption[3] = 0x70;
    
    //填写Data
    char* pData = pOption + 4;
    strcpy(pData, data);
    
    //填写ip头
    struct IPHeader* pIPHeader = (struct IPHeader*)buf;
    //单位是4字节 所以 IPHeader20字节 / 4 = 5   headerlen = 5
    pIPHeader->headerLen = sizeof(struct IPHeader) / 4;
    pIPHeader->version = 4;
    //0代表普通
    pIPHeader->tos = 0;
    //总长度
    pIPHeader->totalLen = size;
    pIPHeader->flagOffset = 0;
    //生存时间
    pIPHeader->ttl = 255;
    //协议类型
    pIPHeader->protocol = IPPROTO_TCP;
    pIPHeader->checksum = 0;
    pIPHeader->srcIP = inet_addr (srcStr);
    pIPHeader->dstIP = inet_addr (dstStr);    
    //计算校验和
    pIPHeader->checksum = checksum ((unsigned short *) pIPHeader, pIPHeader->totalLen);
    
    //填写tcp头
    struct TCPHeader* pTcpHeader = (struct TCPHeader*)(buf + sizeof(struct IPHeader));
    pTcpHeader->srcPort = htons (srcPort);
    pTcpHeader->dstPort = htons (dstPort);
    pTcpHeader->seqNum = 0;
    pTcpHeader->ackNum = 0;
    //tcp header size, contains tcp options 就是5 + 1 = 6  5*4=20是tcp的headerSize 1*4是option
    pTcpHeader->reserved2 = 6;
    pTcpHeader->fin=0;
    pTcpHeader->syn=1;
    pTcpHeader->rst=0;
    pTcpHeader->psh=0;
    pTcpHeader->ack=0;
    pTcpHeader->urg=0;
    pTcpHeader->windownSize = htons (5840);
    pTcpHeader->checksum = 0;
    pTcpHeader->urgPtr = 0;
    
    //计算Tcp校验和
    struct PseudoHeader psh;
    memset(&psh, 0, sizeof(struct PseudoHeader));
    psh.srcIP = inet_addr( srcStr );
    psh.dstIP = inet_addr( dstStr );
    psh.mustBeZero = 0;
    psh.protocol = IPPROTO_TCP;
    psh.len = htons(pTcpHeader->reserved2 * 4 + dataLen);
    
    int pseudoHeaderSize = sizeof(struct PseudoHeader) + pTcpHeader->reserved2 * 4 + dataLen;
    char* pseudogram = (char*)malloc(pseudoHeaderSize);
    memset(pseudogram, 0, pseudoHeaderSize);
    memcpy(pseudogram , (char*) &psh , sizeof(struct PseudoHeader));   
    memcpy(pseudogram + sizeof(struct PseudoHeader) , pTcpHeader , pTcpHeader->reserved2 * 4 + dataLen);
    pTcpHeader->checksum = checksum( (unsigned short*) pseudogram , pseudoHeaderSize);
    
    
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(dstPort);
    sin.sin_addr.s_addr = inet_addr(dstStr);
    ssize_t n = sendto (sockfd, buf, pIPHeader->totalLen ,    0, (struct sockaddr *) &sin, sizeof (sin));
    if (n < 0)
    
        printf("发送错误\\n");
    
    else
    
        printf ("Packet Send. Length : %d \\n" , pIPHeader->totalLen);
    
    free(pseudogram);
    pseudogram = NULL;
    free(buf);
    buf = NULL;

#include "Test.h"
#include "TcpRowSocket.h"

int main()

    int n = sizeof(struct iphdr);
    int n1 = sizeof(struct tcphdrEx);
    int n2 = sizeof(struct IPHeader);
    int n3 = sizeof(struct TCPHeader);
    int n4 = sizeof(struct IPHeader) >> 2;
    
    //test();
   test2();
    return 0;

 

以上是关于RowSocket mac的主要内容,如果未能解决你的问题,请参考以下文章

TCP/IP详解 学习三

1-3:网络初识之网络传输的基本流程TCP首部,IP首部,MAC地址,IP地址等

报文分析1以太网首部

IP:网际协议

主机或者路由器是怎样知道应当在MAC帧的首部填入什么样的硬件地址?(ARP)

TCP UDP 封包过程