일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 이상형 만들기
- 유튜버 김재석
- 성남 코로나 확진자
- 고민정
- 이지혜
- 리리남매
- 김영권 아내
- 미국 금리인하
- 뭉쳐야 찬다
- 스페인 코로나
- 해킹
- 픽크루
- 은혜의 강 교회
- 임영규
- 이태원 클라쓰 15회 예고
- 김영권
- 조희연
- 제넥신
- 불가피
- 최강욱
- 양적완화
- 학교 개학 연기 4월
- 킹덤 고근희
- libtins
- 스콜피온킹
- 금리인하
- 홍혜걸
- 폰폰테스트
- 성남은혜의강교회
- 김재석
- Today
- Total
Dork's port
Checksum 계산하기[소스 코드] (C++) 본문
네트워크에 관련된 프로그래밍을 하다 보면 Checksum을 직접 계산해서 값을 넣어 줘야 하는 경우가 있다.
때문에, 오늘은 그와 관련된 포스팅을 하려 한다.
우선, Checksum을 계산하는 방법에 대해서는 여러 사이트에서 자세히 서술 하고 있으므로 개념적인 내용은 다루지 않을 것이며, 그에 대한 나의 소스코드를 공유하는 것이 목적이다.
#include <netinet/ip.h> #include <netinet/tcp.h> #include <netinet/udp.h> #include <iostream> #include <cstring> #pragma pack(push,1) struct Pseudoheader{ uint32_t srcIP; uint32_t destIP; uint8_t reserved=0; uint8_t protocol; uint16_t TCPLen; }; #pragma pack(pop) #define CARRY 65536 uint16_t calTCPChecksum(uint8_t *data,int dataLen) { //make Pseudo Header struct Pseudoheader pseudoheader; //saved by network byte order //init Pseudoheader struct iphdr *iph=(struct iphdr*)data; struct tcphdr *tcph=(struct tcphdr*)(data+iph->ihl*4); memcpy(&pseudoheader.srcIP,&iph->saddr,sizeof(pseudoheader.srcIP)); memcpy(&pseudoheader.destIP,&iph->daddr,sizeof(pseudoheader.destIP)); pseudoheader.protocol=iph->protocol; pseudoheader.TCPLen=htons(dataLen-(iph->ihl*4)); //Cal pseudoChecksum uint16_t pseudoResult=calculate((uint16_t*)&pseudoheader,sizeof(pseudoheader)); //Cal TCP Segement Checksum tcph->check=0; //set Checksum field 0 uint16_t tcpHeaderResult=calculate((uint16_t*)tcph,ntohs(pseudoheader.TCPLen)); uint16_t checksum; int tempCheck; if((tempCheck=pseudoResult+tcpHeaderResult)>CARRY) checksum=(tempCheck-CARRY) +1; else checksum=tempCheck; checksum=ntohs(checksum^0xffff); //xor checksum tcph->check=checksum; return checksum; } uint16_t calICMPChecksum(uint8_t *data,int dataLen) { //init Pseudoheader struct iphdr *iph=(struct iphdr*)data; struct icmphdr *icmph=(struct icmphdr*)(data+iph->ihl*4); //Cal ICMP Segement Checksum icmph->checksum=0; //set Checksum field 0 uint16_t tcpHeaderResult=calculate((uint16_t*)icmph,(dataLen-(iph->ihl*4))); uint16_t checksum=tcpHeaderResult; checksum=ntohs(checksum^0xffff); //xor checksum icmph->checksum=checksum; return checksum; } uint16_t calUDPChecksum(uint8_t *data, int dataLen) { //make Pseudo Header struct Pseudoheader pseudoheader; //save to network byte order //init Pseudoheader struct iphdr *iph=(struct iphdr*)data; struct udphdr *udph=(struct udphdr*)(data+iph->ihl*4); memcpy(&pseudoheader.srcIP,&iph->saddr,sizeof(pseudoheader.srcIP)); memcpy(&pseudoheader.destIP,&iph->daddr,sizeof(pseudoheader.destIP)); pseudoheader.protocol=iph->protocol; pseudoheader.TCPLen=htons(dataLen-(iph->ihl*4)); //Cal pseudoChecksum uint16_t pseudoResult=calculate((uint16_t*)&pseudoheader,sizeof(pseudoheader)); //Cal TCP Segement Checksum udph->check=0; //set Checksum field 0 uint16_t tcpHeaderResult=calculate((uint16_t*)udph,ntohs(pseudoheader.TCPLen)); uint16_t checksum; int tempCheck; if((tempCheck=pseudoResult+tcpHeaderResult)>CARRY) checksum=(tempCheck-CARRY) +1; else checksum=tempCheck; checksum=ntohs(checksum^0xffff); //xor checksum udph->check=checksum; return checksum; } uint16_t calculate(uint16_t* data, int dataLen) { uint16_t result; int tempChecksum=0; int length; bool flag=false; if((dataLen%2)==0) length=dataLen/2; else { length=(dataLen/2)+1; flag=true; } for (int i = 0; i < length; ++i) // cal 2byte unit { if(i==length-1&&flag) //last num is odd num tempChecksum+=ntohs(data[i]&0x00ff); else tempChecksum+=ntohs(data[i]); if(tempChecksum>CARRY) tempChecksum=(tempChecksum-CARRY)+1; } result=tempChecksum; return result; } uint16_t calIPChecksum(uint8_t* data) { struct iphdr* iph=(struct iphdr*)data; iph->check=0;//set Checksum field 0 uint16_t checksum=calculate((uint16_t*)iph,iph->ihl*4); iph->check=htons(checksum^0xffff);//xor checksum return checksum; }
위의 코드는 linux기반 코드이며, 관련 구조체를 제외하고는 동작 방식은 동일하다.
다만 내가 작성한 로직이 최선의 로직은 아니므로, 위의 코드를 수정하거나 위의 코드는 이해 및 예제 사용 정도로 추천한다.
위의 파일은 원래 작성한 checksum.h 와 checksum.cpp 파일을 게시를 위해 합친 것으로 원본 소스코드는 아래의 명령어를 통해 다운 받을 수 있다.
# git clone https://github.com/JangHanbin/NetworkLib
만약 제대로 다운로드가 되지 않는 다면 git패키지를 설치해주길 바란다. 내가 사용하는 kali linux의 명령어는 아래와 같다.
# apt-get install git
운영체제마다 명령어가 상이할 수 있으므로, 확인후 설치를 해야한다.
위의 소스코드의 사용 방법은 아래와 같으며 자동으로 계산된 checksum값을 패킷의 checksum field에 삽입해 준다.
calIPChecksum(<ip헤더의 시작 포인터>)
calTCPChecksum(<ip헤더의 시작 포인터>,<ip헤더부터 패킷끝 까지의 길이>)
calICMPChecksum(<ip헤더의 시작 포인터>,<ip헤더부터 패킷끝 까지의 길이>)
calUDPChecksum(<ip헤더의 시작 포인터>,<ip헤더부터 패킷끝 까지의 길이>)
위의 소스코드에서 icmp관련 구조체가 안드로이드 컴파일시 오류가 발생하여 따로 선언해 주었으므로, 관련 구조체를 삭제하고 헤더를 추가하여 사용하여도 무방하다.
'Develop' 카테고리의 다른 글
네트워크 각 헤더의 Next Type 파싱하기. (0) | 2017.09.25 |
---|---|
map 출력하기(C++) (0) | 2017.09.24 |
16진수로 값 출력 및 mac address 출력하기 (C++) (0) | 2017.09.22 |
Linux libpcap 을 이용한 packet capture (0) | 2017.09.22 |
invalid operands to binary expression (C++11) (0) | 2017.09.22 |