السلام عليكم ,
في المستوى السابق هنا :
تحدثنا عن العديد من التقنيات في برمجة الشبكات بإستخدام winsock تحديدا , وهنا سنتابع المزيد وشيئا فشيئا بإذن الله .
وهنا أيضا تم التحدث عن تقنية Blocking و Non-Blocking Sockets ,
الحقيقة أنني أكتب برنامج بإستخدام winsock حاليا وأحببت أن أضيف بعض ماأستفيد منه وألخصه للجميع لتعم الفائدة , لذا ربما يكون الكلام غير متناغم تماما , ففي الجزء الأول بدأنا جلسات للتعلم مباشرة لكن حاليا أضيف بعض الملخصات وإن كان هذا يعني الحاجة للتفاعل أيضا .
لندخل في صلب الموضوع :
=================================
في الجزء السابق قبل مدة الأخ Perfect Stranger تحدث عن إمكانية إضافة ال IP Header مع الحزمة المرسلة ليمكن إستلامها من الطرف الآخر للإستفادة من معلومات ال IP Header وحتى ال TCP أو UDP HEADER , المهم في الأمر أن هذه العملية يمكن تطبيقها بإستخدام الدالة setsocketopt بالبارمتر IP_HDRINCL كالتالي :
bOpt = TRUE; ret = setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&bOpt, sizeof(bOpt));
ففي عند هذه النقطة سنحتاج لأن نحسب حسابات ال ip header والذي يليه سواء TCP أم UDP أو حتى ICMP بالطريقة التي نحددها نحن , لكي نغير في معلومات IP Header المرسلة !
الآن هذا عبث حقيقي يمكنك من تغيير عنوان المرسل لو كان من جهازك مثلا بالعنوان 192.168.0.1 فيمكن أن تغيره لأي شيء ليظهر للمستلم كأنه 10.10.10.5 , وأيضا منفذ الإرسال هو غالبا مايستخدم للإستقبال الحزم المردودة من الطرف البعيد .
لتتعرف أكثر على الوضع تحتاج لمعرفة بنية TCP/IP وال udp , "وهي ماسندرسه هنا " وهي كالتالي :
بالنسبة ل IP HEADER :

بالنسبة ل TCP Header :

وأخيرا UDP Header :

الآن لفهم الوضع خذ هذا المثال ل packet مستلمة وراقب المدخلات وقارنها بالبنية :

في البداية نراقب ال IP Header :
أول بايتين وهي الرقم المخزن في الخلية A1 , وهو في هذه الحال 45 , فالرقم 4 يرمز لنسخة بروتوكول IP وهو هنا Ipv4 , ولاحقا في عام 2010 تقريبا سيتم التعامل رسميا ببروتوكول Ipv6 بشكل ققياسي حيث فرقه الرئيسي من Ipv4 هو أن عناوين IP التي يحملها بعرض 128 بت بدل من 32 بت فقط في النسخة الحالية IPv4 .
البايت التالي من 45 وهو الرقم 5 فيرمز لطول IPHeader وهو هنا بالبايتات يعني 5 بايت وهي 5X32 بت = 160 بت .
طول الحزمه وهو موجوده في الخليتين C1 and D1. في هذه الحاله تحملان القيم 00 و C2. 00 تدل على صفر و C2 تدل على 44 بعد تحوبلها من النظام السادس عشري الى النظام العشري .وهذا يدل على ان الحزمه طولها 44 . وبمعرفة IHL وطول الحزمة يمكننا معرفة بدايه الخلايا التي بها ال DATA في الحزمة حيث بدايه الجزء الذي به الDATA = Length-IHL.
الخليه I1 وهي تدل على قيمة المتغير TTL ( Time To Live ) للحزمه والذي ينقص بواحد عند كل موجه Router تمر به الحزمه وعندما تكون قيمة هذا المتغير صفرا فان ذلك يدل على عدم صلاحية الحزمة .
الخلية J1 تدلنا على نوع البروتوكول المستخدم في الحزمة. في هذه الحزمه القيمة هي 06 وهذا يدل على بروتوكول TCP . بالنسبه لدراستنا هذه فاننا معنيون بالحزم من هذا النوع تلك التي تحمل القيمه 06 في الخليه J1. وهذه بعض الامثله على القيم التي يمكن ان تحملها هذه الخليه والبروتوكولات التي تدل عليها :
1 = ICMP 2 = IGMP 6 = TCP 17 = UDP
الآن فلننتقل لمستوى TCP :
عنوان المرسل ( Source IP Address ) الموجود في الخلايا ( M1,N1,O1 and P1 ) في هذه الحاله فان عنوان المرسل هو 172.16.0.9.
عنوان المستقبل ( Destination IP Address ) الموجود في الخلايا ( A2,B2,C2 and D2 ) في هذه الحاله عنوان المستقبل هو 172.16.0.1.
الخليتين ( G2 and H2 ) تدلان على عنوان منفذ البيانات المستقبل للحزمة. في هذه الحاله هي 00 و 17 بعد التحويل الى عشري هي 23 والتي تدل على Telenet. هنالك عناوين عده تدل على بروتوكولات مستخدمه منها
12 FTP 23 Telenet 25 Mail(SMTP) 80 HTTP
الخلايا ( M2,N2,O2 and P2 ) تدل على قيمه المتغير ( ACK# ) اي رقم الحزمة التاليه التي ينتظر مرسل الحزمه استقبالها من المستقبل. في هذه الحاله هي 00 00 00 00 وهذه القيمة تدل على ان هذه الحزمه هي حزمة طلب انشاء اتصال بين الجهازين.
الجزء الاول من الخليه A3 والذي يحوي القيمة 06 يدل على طول ال TCP Header والذي يبدا حيث انتهى ال IP Header. اي انه في هذه الحزمه فان الخلايا (A1 to D2) هي المكونه للIP Header والخلايا ( E2 to L3 ) هي للTCP Header.
الجزء الاخير الذي يهمنا من هذه البيانات موجود في الخلايا ( C3 and D3 ) والتي تستخدم لتدل على حجم الWindow للمرسل حسب اسلوب TCP Sliding Window المشروح سابقا.
***
كما رأينا من الشرح السريع فإن إضافة معلومات IP Header يجب أن تكون دقيقة لتحقق النتائج المطلوبة مباشرة , وماعلينا إلا أن نكتبها لتغلف ونرسلها يدويا قبل البيانات التي نريد إرسالها للمستلم البعيد :
إليكم الكود حدقو فيه جيدا وسأتحدث عنه بعد قليل :
[color= #007f00;]#include <winsock2.h>
[color= #007f00;]#include <ws2tcpip.h>
[color= #007f00;]#include <stdio.h>
[color= #007f00;]#include <stdlib.h>
[color= #007f00;]#define MAX_MESSAGE 4068
[color= #007f00;]#define MAX_PACKET 4096
[color= #007f00;]//
[color= #007f00;]// Set up some default values
[color= #007f00;]//
[color= #007f00;]#define DEFAULT_PORT 5150
[color= #007f00;]#define DEFAULT_IP "10.0.0.1"
[color= #007f00;]#define DEFAULT_COUNT 5
[color= #007f00;]#define DEFAULT_MESSAGE "This is a test"
[color= #007f00;]//
[color= #007f00;]// Define the IP header. Make the version and length fields one
[color= #007f00;]// character since we can't declare two 4-bit fields without
[color= #007f00;]// the compiler aligning them on at least a 1-byte boundary.
[color= #007f00;]//
[color= #0000ff;]typedef [color= #0000ff;]struct ip_hdr
[color= #000000;]{
[color= #0000ff;]unsigned [color= #0000ff;]char ip_verlen; [color= #007f00;]// IP version & length
[color= #0000ff;]unsigned [color= #0000ff;]char ip_tos; [color= #007f00;]// IP type of service
[color= #0000ff;]unsigned [color= #0000ff;]short ip_totallength; [color= #007f00;]// Total length
[color= #0000ff;]unsigned [color= #0000ff;]short ip_id; [color= #007f00;]// Unique identifier
[color= #0000ff;]unsigned [color= #0000ff;]short ip_offset; [color= #007f00;]// Fragment offset field
[color= #0000ff;]unsigned [color= #0000ff;]char ip_ttl; [color= #007f00;]// Time to live
[color= #0000ff;]unsigned [color= #0000ff;]char ip_protocol; [color= #007f00;]// Protocol(TCP, UDP, etc.)
[color= #0000ff;]unsigned [color= #0000ff;]short ip_checksum; [color= #007f00;]// IP checksum
[color= #0000ff;]unsigned [color= #0000ff;]int ip_srcaddr; [color= #007f00;]// Source address
[color= #0000ff;]unsigned [color= #0000ff;]int ip_destaddr; [color= #007f00;]// Destination address
[color= #000000;]} IP_HDR, [color= #000000;]*PIP_HDR, FAR[color= #000000;]* LPIP_HDR;
[color= #007f00;]//
[color= #007f00;]// Define the UDP header
[color= #007f00;]//
[color= #0000ff;]typedef [color= #0000ff;]struct udp_hdr
[color= #000000;]{
[color= #0000ff;]unsigned [color= #0000ff;]short src_portno; [color= #007f00;]// Source port number
[color= #0000ff;]unsigned [color= #0000ff;]short dst_portno; [color= #007f00;]// Destination port number
[color= #0000ff;]unsigned [color= #0000ff;]short udp_length; [color= #007f00;]// UDP packet length
[color= #0000ff;]unsigned [color= #0000ff;]short udp_checksum; [color= #007f00;]// UDP checksum (optional)
[color= #000000;]} UDP_HDR, [color= #000000;]*PUDP_HDR;
[color= #007f00;]//
[color= #007f00;]// Global variables
[color= #007f00;]//
[color= #0000ff;]unsigned [color= #0000ff;]long dwToIP, [color= #007f00;]// IP to send to
dwFromIP; [color= #007f00;]// IP to send from (spoof)
[color= #0000ff;]unsigned [color= #0000ff;]short iToPort, [color= #007f00;]// Port to send to
iFromPort; [color= #007f00;]// Port to send from (spoof)
DWORD dwCount; [color= #007f00;]// Number of times to send
[color= #0000ff;]char strMessage[color= #000000;][MAX_MESSAGE[color= #000000;]]; [color= #007f00;]// Message to send
iToPort [color= #000000;]= DEFAULT_PORT;
iFromPort [color= #000000;]= DEFAULT_PORT;
dwToIP [color= #000000;]= inet_addr[color= #000000;](DEFAULT_IP[color= #000000;]);
dwFromIP [color= #000000;]= inet_addr[color= #000000;](DEFAULT_IP[color= #000000;]);
dwCount [color= #000000;]= DEFAULT_COUNT;
strcpy[color= #000000;](strMessage, DEFAULT_MESSAGE[color= #000000;]);
[color= #007f00;]//
[color= #007f00;]// Function: checksum
[color= #007f00;]//
[color= #007f00;]// Description:
[color= #007f00;]// This function calculates the 16-bit one's complement sum
[color= #007f00;]// for the supplied buffer
[color= #007f00;]//
USHORT checksum[color= #000000;](USHORT [color= #000000;]*buffer, [color= #0000ff;]int size[color= #000000;])
[color= #000000;]{
[color= #0000ff;]unsigned [color= #0000ff;]long cksum[color= #000000;]=[color= #ff0000;]0;
[color= #0000ff;]while [color= #000000;](size [color= #000000;]> [color= #ff0000;]1[color= #000000;])
[color= #000000;]{
cksum [color= #000000;]+[color= #000000;]= [color= #000000;]*buffer[color= #000000;]++;
size [color= #000000;]-[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](USHORT[color= #000000;]);
[color= #000000;]}
[color= #0000ff;]if [color= #000000;](size[color= #000000;])
[color= #000000;]{
cksum [color= #000000;]+[color= #000000;]= [color= #000000;]*[color= #000000;](UCHAR[color= #000000;]*[color= #000000;])buffer;
[color= #000000;]}
cksum [color= #000000;]= [color= #000000;](cksum [color= #000000;]>> [color= #ff0000;]16[color= #000000;]) [color= #000000;]+ [color= #000000;](cksum [color= #000000;]& 0xffff[color= #000000;]);
cksum [color= #000000;]+[color= #000000;]= [color= #000000;](cksum [color= #000000;]>>[color= #ff0000;]16[color= #000000;]);
[color= #0000ff;]return [color= #000000;](USHORT[color= #000000;])[color= #000000;](~cksum[color= #000000;]);
[color= #000000;]}
[color= #0000ff;]int main[color= #000000;]([color= #0000ff;]int argc, [color= #0000ff;]char [color= #000000;]**argv[color= #000000;])
[color= #000000;]{
WSADATA wsd;
SOCKET s;
[color= #0000ff;]BOOL bOpt;
[color= #0000ff;]struct sockaddr_in remote; [color= #007f00;]// IP addressing structures
IP_HDR ipHdr;
UDP_HDR udpHdr;
[color= #0000ff;]int ret;
DWORD i;
[color= #0000ff;]unsigned [color= #0000ff;]short iTotalSize, [color= #007f00;]// Lots of sizes needed to fill
iUdpSize, [color= #007f00;]// the various headers with
iUdpChecksumSize,
iIPVersion,
iIPSize,
cksum [color= #000000;]= [color= #ff0000;]0;
[color= #0000ff;]char buf[color= #000000;][MAX_PACKET[color= #000000;]],
[color= #000000;]*ptr [color= #000000;]= NULL;
IN_ADDR addr;
[color= #007f00;]// Parse command line arguments, and print them out
[color= #007f00;]//
ValidateArgs[color= #000000;](argc, argv[color= #000000;]);
addr.[color= #808000;]S_un.[color= #808000;]S_addr [color= #000000;]= dwFromIP;
printf[color= #000000;]([color= #A31515;]"From IP: <%s>[color= #A31515; font-weight: bold;]n Port: %d[color= #A31515; font-weight: bold;]n", inet_ntoa[color= #000000;](addr[color= #000000;]),
iFromPort[color= #000000;]);
addr.[color= #808000;]S_un.[color= #808000;]S_addr [color= #000000;]= dwToIP;
printf[color= #000000;]([color= #A31515;]"To IP: <%s>[color= #A31515; font-weight: bold;]n Port: %d[color= #A31515; font-weight: bold;]n", inet_ntoa[color= #000000;](addr[color= #000000;]),
iToPort[color= #000000;]);
printf[color= #000000;]([color= #A31515;]"Message: [%s][color= #A31515; font-weight: bold;]n", strMessage[color= #000000;]);
printf[color= #000000;]([color= #A31515;]"Count: %d[color= #A31515; font-weight: bold;]n", dwCount[color= #000000;]);
[color= #0000ff;]if [color= #000000;](WSAStartup[color= #000000;](MAKEWORD[color= #000000;]([color= #ff0000;]2,[color= #ff0000;]2[color= #000000;]), [color= #000000;]&wsd[color= #000000;]) [color= #000000;]![color= #000000;]= [color= #ff0000;]0[color= #000000;])
[color= #000000;]{
printf[color= #000000;]([color= #A31515;]"WSAStartup() failed: %d[color= #A31515; font-weight: bold;]n", GetLastError[color= #000000;]([color= #000000;])[color= #000000;]);
[color= #0000ff;]return [color= #ff0000;]-1;
[color= #000000;]}
[color= #007f00;]// Creating a raw socket
[color= #007f00;]//
s [color= #000000;]= WSASocket[color= #000000;](AF_INET, SOCK_RAW, IPPROTO_UDP, NULL, [color= #ff0000;]0,[color= #ff0000;]0[color= #000000;]);
[color= #0000ff;]if [color= #000000;](s [color= #000000;]== INVALID_SOCKET[color= #000000;])
[color= #000000;]{
printf[color= #000000;]([color= #A31515;]"WSASocket() failed: %d[color= #A31515; font-weight: bold;]n", WSAGetLastError[color= #000000;]([color= #000000;])[color= #000000;]);
[color= #0000ff;]return [color= #ff0000;]-1;
[color= #000000;]}
[color= #007f00;]// Enable the IP header include option
[color= #007f00;]//
bOpt [color= #000000;]= TRUE;
ret [color= #000000;]= setsockopt[color= #000000;](s, IPPROTO_IP, IP_HDRINCL, [color= #000000;]([color= #0000ff;]char [color= #000000;]*[color= #000000;])[color= #000000;]&bOpt,
[color= #0000ff;]sizeof[color= #000000;](bOpt[color= #000000;])[color= #000000;]);
[color= #0000ff;]if [color= #000000;](ret [color= #000000;]== SOCKET_ERROR[color= #000000;])
[color= #000000;]{
printf[color= #000000;]([color= #A31515;]"setsockopt(IP_HDRINCL) failed: %d[color= #A31515; font-weight: bold;]n", WSAGetLastError[color= #000000;]([color= #000000;])[color= #000000;]);
[color= #0000ff;]return [color= #ff0000;]-1;
[color= #000000;]}
[color= #007f00;]// Initalize the IP header
[color= #007f00;]//
iTotalSize [color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr[color= #000000;]) [color= #000000;]+ [color= #0000ff;]sizeof[color= #000000;](udpHdr[color= #000000;]) [color= #000000;]+ strlen[color= #000000;](strMessage[color= #000000;]);
iIPVersion [color= #000000;]= [color= #ff0000;]4;
iIPSize [color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr[color= #000000;]) [color= #000000;]/ [color= #0000ff;]sizeof[color= #000000;]([color= #0000ff;]unsigned [color= #0000ff;]long[color= #000000;]);
[color= #007f00;]//
[color= #007f00;]// IP version goes in the high-order 4 bits of ip_verlen. The
[color= #007f00;]// IP header length (in 32-bit words) goes in the lower 4 bits.
[color= #007f00;]//
ipHdr.[color= #808000;]ip_verlen [color= #000000;]= [color= #000000;](iIPVersion [color= #000000;]<< [color= #ff0000;]4[color= #000000;]) [color= #000000;]| iIPSize;
ipHdr.[color= #808000;]ip_tos [color= #000000;]= [color= #ff0000;]0; [color= #007f00;]// IP type of service
ipHdr.[color= #808000;]ip_totallength [color= #000000;]= htons[color= #000000;](iTotalSize[color= #000000;]); [color= #007f00;]// Total packet len
ipHdr.[color= #808000;]ip_id [color= #000000;]= [color= #ff0000;]0; [color= #007f00;]// Unique identifier: set to 0
ipHdr.[color= #808000;]ip_offset [color= #000000;]= [color= #ff0000;]0; [color= #007f00;]// Fragment offset field
ipHdr.[color= #808000;]ip_ttl [color= #000000;]= [color= #ff0000;]128; [color= #007f00;]// Time to live
ipHdr.[color= #808000;]ip_protocol [color= #000000;]= 0x11; [color= #007f00;]// Protocol(UDP)
ipHdr.[color= #808000;]ip_checksum [color= #000000;]= [color= #ff0000;]0; [color= #007f00;]// IP checksum
ipHdr.[color= #808000;]ip_srcaddr [color= #000000;]= dwFromIP; [color= #007f00;]// Source address
ipHdr.[color= #808000;]ip_destaddr [color= #000000;]= dwToIP; [color= #007f00;]// Destination address
[color= #007f00;]//
[color= #007f00;]// Initalize the UDP header
[color= #007f00;]//
iUdpSize [color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](udpHdr[color= #000000;]) [color= #000000;]+ strlen[color= #000000;](strMessage[color= #000000;]);
udpHdr.[color= #808000;]src_portno [color= #000000;]= htons[color= #000000;](iFromPort[color= #000000;]);
udpHdr.[color= #808000;]dst_portno [color= #000000;]= htons[color= #000000;](iToPort[color= #000000;]);
udpHdr.[color= #808000;]udp_length [color= #000000;]= htons[color= #000000;](iUdpSize[color= #000000;]);
udpHdr.[color= #808000;]udp_checksum [color= #000000;]= [color= #ff0000;]0;
[color= #007f00;]//
[color= #007f00;]// Build the UDP pseudo-header for calculating the UDP checksum.
[color= #007f00;]// The pseudo-header consists of the 32-bit source IP address,
[color= #007f00;]// the 32-bit destination IP address, a zero byte, the 8-bit
[color= #007f00;]// IP protocol field, the 16-bit UDP length, and the UDP
[color= #007f00;]// header itself along with its data (padded with a 0 if
[color= #007f00;]// the data is odd length).
[color= #007f00;]//
iUdpChecksumSize [color= #000000;]= [color= #ff0000;]0;
ptr [color= #000000;]= buf;
ZeroMemory[color= #000000;](buf, MAX_PACKET[color= #000000;]);
memcpy[color= #000000;](ptr, [color= #000000;]&ipHdr.[color= #808000;]ip_srcaddr, [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_srcaddr[color= #000000;])[color= #000000;]);
ptr [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_srcaddr[color= #000000;]);
iUdpChecksumSize [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_srcaddr[color= #000000;]);
memcpy[color= #000000;](ptr, [color= #000000;]&ipHdr.[color= #808000;]ip_destaddr, [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_destaddr[color= #000000;])[color= #000000;]);
ptr [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_destaddr[color= #000000;]);
iUdpChecksumSize [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_destaddr[color= #000000;]);
ptr[color= #000000;]++;
iUdpChecksumSize [color= #000000;]+[color= #000000;]= [color= #ff0000;]1;
memcpy[color= #000000;](ptr, [color= #000000;]&ipHdr.[color= #808000;]ip_protocol, [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_protocol[color= #000000;])[color= #000000;]);
ptr [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_protocol[color= #000000;]);
iUdpChecksumSize [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr.[color= #808000;]ip_protocol[color= #000000;]);
memcpy[color= #000000;](ptr, [color= #000000;]&udpHdr.[color= #808000;]udp_length, [color= #0000ff;]sizeof[color= #000000;](udpHdr.[color= #808000;]udp_length[color= #000000;])[color= #000000;]);
ptr [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](udpHdr.[color= #808000;]udp_length[color= #000000;]);
iUdpChecksumSize [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](udpHdr.[color= #808000;]udp_length[color= #000000;]);
memcpy[color= #000000;](ptr, [color= #000000;]&udpHdr, [color= #0000ff;]sizeof[color= #000000;](udpHdr[color= #000000;])[color= #000000;]);
ptr [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](udpHdr[color= #000000;]);
iUdpChecksumSize [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](udpHdr[color= #000000;]);
[color= #0000ff;]for[color= #000000;](i [color= #000000;]= [color= #ff0000;]0; i [color= #000000;]< strlen[color= #000000;](strMessage[color= #000000;]); i[color= #000000;]++, ptr[color= #000000;]++[color= #000000;])
[color= #000000;]*ptr [color= #000000;]= strMessage[color= #000000;][i[color= #000000;]];
iUdpChecksumSize [color= #000000;]+[color= #000000;]= strlen[color= #000000;](strMessage[color= #000000;]);
cksum [color= #000000;]= checksum[color= #000000;]([color= #000000;](USHORT [color= #000000;]*[color= #000000;])buf, iUdpChecksumSize[color= #000000;]);
udpHdr.[color= #808000;]udp_checksum [color= #000000;]= cksum;
[color= #007f00;]//
[color= #007f00;]// Now assemble the IP and UDP headers along with the data
[color= #007f00;]// so we can send it
[color= #007f00;]//
ZeroMemory[color= #000000;](buf, MAX_PACKET[color= #000000;]);
ptr [color= #000000;]= buf;
memcpy[color= #000000;](ptr, [color= #000000;]&ipHdr, [color= #0000ff;]sizeof[color= #000000;](ipHdr[color= #000000;])[color= #000000;]); ptr [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](ipHdr[color= #000000;]);
memcpy[color= #000000;](ptr, [color= #000000;]&udpHdr, [color= #0000ff;]sizeof[color= #000000;](udpHdr[color= #000000;])[color= #000000;]); ptr [color= #000000;]+[color= #000000;]= [color= #0000ff;]sizeof[color= #000000;](udpHdr[color= #000000;]);
memcpy[color= #000000;](ptr, strMessage, strlen[color= #000000;](strMessage[color= #000000;])[color= #000000;]);
[color= #007f00;]// Apparently, this SOCKADDR_IN structure makes no difference.
[color= #007f00;]// Whatever we put as the destination IP addr in the IP header
[color= #007f00;]// is what goes. Specifying a different destination in remote
[color= #007f00;]// will be ignored.
[color= #007f00;]//
remote.[color= #808000;]sin_family [color= #000000;]= AF_INET;
remote.[color= #808000;]sin_port [color= #000000;]= htons[color= #000000;](iToPort[color= #000000;]);
remote.[color= #808000;]sin_addr.[color= #808000;]s_addr [color= #000000;]= dwToIP;
[color= #0000ff;]for[color= #000000;](i [color= #000000;]= [color= #ff0000;]0; i [color= #000000;]< dwCount; i[color= #000000;]++[color= #000000;])
[color= #000000;]{
ret [color= #000000;]= sendto[color= #000000;](s, buf, iTotalSize, [color= #ff0000;]0, [color= #000000;](SOCKADDR [color= #000000;]*[color= #000000;])[color= #000000;]&remote,
[color= #0000ff;]sizeof[color= #000000;](remote[color= #000000;])[color= #000000;]);
[color= #0000ff;]if [color= #000000;](ret [color= #000000;]== SOCKET_ERROR[color= #000000;])
[color= #000000;]{
printf[color= #000000;]([color= #A31515;]"sendto() failed: %d[color= #A31515; font-weight: bold;]n", WSAGetLastError[color= #000000;]([color= #000000;])[color= #000000;]);
break;
[color= #000000;]}
[color= #0000ff;]else
printf[color= #000000;]([color= #A31515;]"sent %d bytes[color= #A31515; font-weight: bold;]n", ret[color= #000000;]);
[color= #000000;]}
closesocket[color= #000000;](s[color= #000000;]);
WSACleanup[color= #000000;]([color= #000000;]);
[color= #0000ff;]return [color= #ff0000;]0;
[color= #000000;]}

-1.gif)