Server : VM
Client : PC
(Client : 집 VM IP 이므로 수정 필요할 수 있음)
============================================
⇒ TCP 헤더의 Data 필드에서 Option 의 유무를 확인하고 Segment 페이로드 시작 위치를 정확히 찾아야 함
(중요!!) Multithread Server ↔ Client 채팅에서 데이터 옵셋 및 페이로드를 추출하기 위한 packet_handler 분석
// pkt_data 를 Ethernet Header 로 type casting
EtherHeader* pEther = (EtherHeader*)pkt_data;
// pkt_data 에 EtherHeader offset 만큼 더해 IP Header 위치를 찾기
IpHeader* pIpHeader = (IpHeader*)(pkt_data + sizeof(EtherHeader));
// ipv4 가 아닐 경우 종료
// == (if(ntohs(pEther->type) != 0x0800)
if (pEther->type != 0x0008)
return;
// TCP 헤더가 아닐 경우 종료
if (pIpHeader->protocol != 6)
return;
// version 과 IHL 로 분리하고(비트 연산), IHL 값에 4바이트 단위를 적용하여
// IP Header 길이를 구한다.
int ipHeaderLen = (pIpHeader->verIhl & 0x0F) * 4;
// pkt_data 에 EtherHeader offset + ipHeader offset 만큼 더해 TCP Header 위치 찾기
TcpHeader* pTcp =
(TcpHeader*)(pkt_data + sizeof(EtherHeader) + ipHeaderLen);
// TCP 헤더에서 출발지나 목적지 포트가 내가 찾으려는 포트(25000) 이 아닐 경우 종료
if (ntohs(pTcp->srcPort) != 25000 &&
ntohs(pTcp->dstPort) != 25000)
return;
// 출발지 IP:PORT -> 목적지 IP:PORT 출력
printf("%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\\n",
pIpHeader->srcIp[0], pIpHeader->srcIp[1],
pIpHeader->srcIp[2], pIpHeader->srcIp[3],
ntohs(pTcp->srcPort),
pIpHeader->dstIp[0], pIpHeader->dstIp[1],
pIpHeader->dstIp[2], pIpHeader->dstIp[3],
ntohs(pTcp->dstPort)
);
// pTcp->data는 상위 4비트가 Data Offset, 하위 4비트가 Reserved이므로
// 상위 4비트만 추출하기 위해 우측 시프트 후 4바이트 단위로 변환
int tcpHeaderSize = ((pTcp->data >> 4 & 0x0F) * 4);
// TCP Payload 위치 계산
// pkt_data + Ether Header + ipHeaderLen + tcpHeaderSize
char* pPayload = (char*)(pkt_data + sizeof(EtherHeader) +
ipHeaderLen + tcpHeaderSize);
// segment size 계산
/* IP 총 길이 - IP 헤더 길이 - TCP 헤더 길이 = TCP Payload (세그먼트 데이터) 크기
*/
printf("Segment size: %d(Frame length: %d)\\n",
ntohs(pIpHeader->length) - ipHeaderLen - tcpHeaderSize,
header->len);
// segment 버퍼에 pPayload 에서 segment 길이만큼 문자열을 추출해 저장
char szMessage[2048] = { 0 };
memcpy_s(szMessage, sizeof(szMessage), pPayload,
ntohs(pIpHeader->length) - ipHeaderLen - tcpHeaderSize);
puts(szMessage);