Winapi: Sending arp reply - c

I'm new with Winapi and currently trying to send arp packets using raw sockets. Here is my code:
#include "winsock2.h"
#include "windows.h"
#include "time.h"
#include "stdio.h"
#include "ws2tcpip.h"
#include "conio.h"
#define ETH_HW_ADDR_LEN 6
#define IP_ADDR_LEN 4
#define ARP_FRAME_TYPE 0x0806
#define ETHER_HW_TYPE 1
#define IP_PROTO_TYPE 0x0800
#define OP_ARP_REPLY 2
struct arp_packet {
u_short hw_type; // Hardware type (HTYPE)
u_short prot_type; // Protocol type (PTYPE)
u_char hw_addr_size; // Hardware length (HLEN)
u_char prot_addr_size; // Protocol length (PLEN)
u_short op; // Operation
u_char sndr_hw_addr[ETH_HW_ADDR_LEN]; // Sender hardware address (SHA)
u_char sndr_ip_addr[IP_ADDR_LEN]; // Sender protocol address (SPA)
u_char rcpt_hw_addr[ETH_HW_ADDR_LEN]; // Target hardware address (THA)
u_char rcpt_ip_addr[IP_ADDR_LEN]; // Target protocol address (TPA)
};
void get_ip_addr( struct in_addr* in_addr, char* str ){
struct hostent *hostp;
in_addr->s_addr = inet_addr(str);
if ( in_addr->s_addr == -1 ){
if( (hostp = gethostbyname(str)))
{memcpy (in_addr, hostp->h_addr, hostp->h_length);}
else {
fprintf( stderr, "send_arp: unknown host [%s].\n", str ) ;
exit(1);
}
}
} ; // get_ip_addr
int main()
{
struct in_addr src_in_addr, targ_in_addr;
struct arp_packet pkt;
char *sender_mac = "AA-AA-AA-AA-AA-AA";
char *receiver_mac = "88-9F-FA-6E-64-3Q";
SOCKET s;
int optval;
hostent *server;
WSADATA wsock;
if (WSAStartup(MAKEWORD(2,2),&wsock) != 0)
{
fprintf(stderr,"WSAStartup() failed");
exit(EXIT_FAILURE);
}
printf("Initialised successfully.\n");
if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==SOCKET_ERROR)
{
printf("Creation of raw socket failed %d\n.", WSAGetLastError());
return 0;
}
printf("Raw TCP Socket Created successfully.\n");
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval))==SOCKET_ERROR)
{
printf("failed to set socket in raw mode %d\n.", WSAGetLastError());
return 0;
}
printf("Successful.\n");
pkt.hw_type = htons(ETHER_HW_TYPE);
pkt.prot_type = htons(IP_PROTO_TYPE);
pkt.hw_addr_size = ETH_HW_ADDR_LEN;
pkt.prot_addr_size = IP_ADDR_LEN;
pkt.op = htons(OP_ARP_REPLY);
strcpy((char *)pkt.sndr_hw_addr, sender_mac);
strcpy((char *)pkt.rcpt_hw_addr, receiver_mac);
get_ip_addr( &src_in_addr, "192.168.1.53");
get_ip_addr( &targ_in_addr, "192.168.1.113");
memcpy( pkt.sndr_ip_addr, &src_in_addr, IP_ADDR_LEN);
memcpy( pkt.rcpt_ip_addr, &targ_in_addr, IP_ADDR_LEN);
if((sendto(s , (const char* )&pkt , sizeof(pkt), 0, 0, 0))==SOCKET_ERROR)
{
printf("Error sending Packet : %d\n", WSAGetLastError());
}
return 0;
}
As this is just for educational purposes I hardcoded MAC and ip addresses As you can see I'm trying to send ARP reply to some ip address. I'm using cygwin to compile, and the output is:
$ ./test.exe
Initialised successfully.
Raw TCP Socket Created successfully.
Successful.
Error sending Packet : 10057
I've searched and 10057 means Socket is not connected. But I don't know why I'm getting this error. Then I decided to change sendto function to this:
SOCKADDR_IN dest;
if((sendto(s , (const char* )&pkt , sizeof(pkt), 0, (SOCKADDR *)&dest, sizeof(dest)))==SOCKET_ERROR)
just to see what would have happened, I still got error but it was different 10047. Which means that Address family not supported by protocol family. But in msdn documentation I've seen that This is a possible value when the af parameter is AF_UNSPEC, AF_INET, or AF_INET6 and the type parameter is SOCK_RAW or unspecified I'm using windows 7. Thanks.

Related

C Networking: Sendto() returning Errno 22, EINVAL

I'm attempting to generate a packet from scratch with Layer 2, 3, and 4 components (namely Ethernet, IP, and UDP). My socket is configured to use SOCK_RAW as the type and IPPROTO_RAW as the protocol, so that my program can be used to send different protocols at a later date. I've strictly abided by the sendto(2) man page (https://linux.die.net/man/2/sendto), however, I still seem to be having troubles transmitting a packet over local host. The error returned by my program is 22, or EINVAL, indicating that I've passed an incorrect argument.
I've already used Sockets sendto() returning EINVAL and Socket programming: sendto always fails with errno 22 (EINVAL) in attempt to resolve my problem. I've even switched the socket to use SOCK_DGRAM as the type and IPPROTO_UDP as the protocol to see if it was something to do with the socket (though I don't believe this would have prompted an incorrect argument response).
My code is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/ip.h>
#include <netinet/ether.h>
#include <netinet/udp.h>
#include <sys/socket.h>
#include <errno.h>
#define BUFFER 1024
int main(int argc, char *argv[]) {
/* Socket Creation */
int sockfd;
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("Socket");
exit(EXIT_FAILURE);
}
// This will hold all of the packet's contents
char sendbuf[BUFFER];
/* Address Stuff */
// Specify Address
in_addr_t address = inet_addr("127.0.0.1");
// Specifying Address for Sendto()
struct sockaddr_in sendto_addr;
memset(&sendto_addr, 0, sizeof(sendto_addr));
sendto_addr.sin_family = AF_INET;
sendto_addr.sin_port = htons(9623); // Make sure the port isn't contested
sendto_addr.sin_addr.s_addr = address;
// Size of whole packet
size_t total_len = 0;
/* LAYER 2 */
// Ethernet Header Configuration
struct ether_header *ether = (struct ether_header *)sendbuf;
int i;
for (i = 0; i < 6; ++i) {
ether -> ether_dhost[i] = 0x00; // Temporary data fill
ether -> ether_shost[i] = 0x00; // Temporary data fill
}
ether -> ether_type = ETHERTYPE_IP;
total_len += sizeof(struct ether_header);
/* LAYER 3 */
// IP Header Configuration
struct ip *ip = (struct ip *)(sendbuf + sizeof(struct ether_header));
ip -> ip_hl = 5;
ip -> ip_v = 4;
ip -> ip_tos = 0;
ip -> ip_p = 17;
ip -> ip_ttl = 255;
ip -> ip_src.s_addr = address;
ip -> ip_dst.s_addr = address;
total_len += sizeof(struct ip);
/* LAYER 4 */
// UDP Header Configuration
struct udphdr *udp = (struct udphdr *)(sendbuf + sizeof(struct ether_header) + \
sizeof(struct ip));
udp -> source = 123; // Gibberish to fill in later
udp -> dest = 321; // Gibberish to fill in later
udp -> check = 0;
total_len += sizeof(struct udphdr);
/* Giberrish Packet Data */
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
sendbuf[total_len++] = 0x00;
/* Fill in Rest of Headers */
udp -> len = htons(total_len - sizeof(struct ether_header) - sizeof(struct ip));
ip -> ip_len = htons(total_len - sizeof(struct ether_header));
/* Send Packet */ // ERROR OCCURS HERE
printf("Sockfd is %d\n", sockfd);
printf("Total length is %d\n", total_len);
if (sendto(sockfd, sendbuf, total_len, 0, (const struct sockaddr*)&sendto_addr, \
sizeof(sendto_addr)) < 0) {
printf("Error sending packet: Error %d.\n", errno);
perror("sendto Error");
exit(EXIT_FAILURE);
}
close(sockfd);
}
The precise console message states:
Sockfd is 3
Total length is 46
Error sending packet: Error 22.
sendto Error: Invalid argument
Eureka! It was actually this line:
if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
perror("Socket");
exit(EXIT_FAILURE);
}
Which should have been
if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("Socket");
exit(EXIT_FAILURE);
}
Why this fixed the problem? Great question, would love to see someone's response on the subject :P

Recv() not working in separate thread, C socket programming

I am having some issues with the recv() function returning a -1 in a C program with threading. The basis of the program is to receive a few request packets in one thread and having a second thread send out a multicast to all registered clients.
Below is the code for my server:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <arpa/inet.h>
#include <pthread.h>
#define SERVER_PORT 5654
#define MAX_LINE 256
#define MAX_PENDING 5
/*structure of the packet*/
struct packet{
short type;
char data[MAX_LINE];
};
struct data_packet{
short header;
char data[MAX_LINE];
};
/* structure of Registration Table */
struct registrationTable{
int port;
char name[MAX_LINE];
int req_no;
};
struct global_table{
int sockid;
int reqno;
};
void *join_handler(struct global_table *rec){
int new_s;
struct packet packet_reg;
new_s = rec->sockid;
printf("In thread: %i\n",new_s);
printf("In thread: %i\n",rec->reqno);
if(recv(new_s,&packet_reg,sizeof(packet_reg),0)<0){
printf("\ncouldnt receive first reg packet\n");
exit(1);
}
pthread_exit(NULL);
}
int main(int argc, char* argv[])
{
/* initilizing all of the packets*/
struct packet packet_reg;
struct registrationTable table[10];
struct global_table record[20];
struct sockaddr_in sin;
struct sockaddr_in clientAddr;
char buf[MAX_LINE];
int s, new_s;
int len;
int i;
struct hostent *he;
struct in_addr **addr_list;
pthread_t threads[2];
/* setup passive open */
if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
perror("tcpserver: socket");
exit(1);
}
/* build address data structure */
bzero((char*)&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(SERVER_PORT);
if(bind(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){
perror("tcpclient: bind");
exit(1);
}
listen(s, MAX_PENDING);
/* wait for connection, then receive and print text */
while(1){
if((new_s = accept(s, (struct sockaddr *)&clientAddr, &len)) < 0){
perror("tcpserver: accept");
exit(1);
}
/* print the port of the client*/
printf("\n Client's port is %d \n", ntohs(clientAddr.sin_port));
/* receive the first registration packet*/
if(recv(new_s,&packet_reg,sizeof(packet_reg),0)<0){
printf("\ncouldnt receive first reg packet\n");
exit(1);
}
struct global_table client_info;
client_info.sockid = ntohs(clientAddr.sin_port);
client_info.reqno = 1;
pthread_create(&threads[0],NULL,join_handler, &client_info);
}
}
Client:
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#define SERVER_PORT 5654
#define MAX_LINE 256
/*structure of the packet*/
struct packet{
short type;
char data[MAX_LINE];
};
struct data_packet{
short header;
char data[MAX_LINE];
};
int main(int argc, char* argv[])
{
struct packet packet_reg;
struct hostent *hp;
struct sockaddr_in sin;
char *host;
char buf[MAX_LINE];
int s;
int len;
char hostname[1024];
hostname[1023] = '\0';
if(argc == 2){
host = argv[1];
}
else{
fprintf(stderr, "usage:newclient server\n");
exit(1);
}
/* translate host name into peer's IP address */
hp = gethostbyname(host);
if(!hp){
fprintf(stderr, "unkown host: %s\n", host);
exit(1);
}
/* active open */
if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){
perror("tcpclient: socket");
exit(1);
}
/* build address data structure */
bzero((char*)&sin, sizeof(sin));
sin.sin_family = AF_INET;
bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
sin.sin_port = htons(SERVER_PORT);
if(connect(s,(struct sockaddr *)&sin, sizeof(sin)) < 0){
perror("tcpclient: connect");
close(s);
exit(1);
}
/* main loop: get and send lines of text
all you have to do to start the program is
enter any key */
while(fgets(buf, sizeof(buf), stdin)){
/* Find the hostname and print it*/
gethostname(hostname, 1023);
printf("Hostname: %s\n", hostname);
/* populate the info for the first registration packet*/
packet_reg.type = htons(121);
strcpy(packet_reg.data,hostname);
/*send the registration packet to the server*/
if(send(s,&packet_reg,sizeof(packet_reg),0)<0){
printf("\nsend failed\n");
exit(1);
}
/* Print the contents of the first registration packet*/
printf("Sent 1st reg packet data: %s\n",packet_reg.data );
printf("Sent 1st reg packet type: %i\n",ntohs(packet_reg.type));
/* create the second registration packet.
I created separate packets for this so
it was clearer*/
packet_reg.type = htons(121);
strcpy(packet_reg.data,hostname);
/*send the second registration packet to the server*/
if(send(s,&packet_reg,sizeof(packet_reg),0)<0){
printf("\nsend failed\n");
exit(1);
}
/* Print the contents of the second registration packet*/
printf("Sent 2nd reg packet data: %s\n",packet_reg.data );
printf("Sent 2nd reg packet type: %i\n",ntohs(packet_reg.type));
}
}
So Basically, I am creating the connection and wait to receive the first registration packet (packet_reg). This works and I receive the packet. I then send control of the program to the thread. However, while the "rec" variable correctly passes the information, the subsequent receive does not work and exits with a value less than 0.
Other information: The packets are all sent and received correctly, but the client's port, printed from
printf("\n Client's port is %d \n", ntohs(clientAddr.sin_port));
is listed as 0. I am not sure if this is a problem, but the code works fine when all of the receives are in the main function.
Another issue could be that I get the following warning:
passing argument 3 pf pthread_create from incompatible pointer type expected 'void * (*) (void *)' but argument of type 'void * (*) (struct global_table*)'
I have researched this warning and know that it has to do with receiving the data as void and then casting. However, the data is being sent to the thread properly when I print from there to check.
Basically, the problem is that while I can receive the packets from the client outside the thread, with the same statements, when I am inside the thread the packets are not received and recv() returns -1.
I accidentally set the receive to the port and not the socket. I am a dummy. I know that a lot of you were telling me how bad the code is constructed regarding TCP conventions. I am building off of code for an assignment, nothing I can do about the professor telling us that this is the way to do it.

Multicasting on Ubuntu

My situation is as follows:
I have a windows machine running a UDP Multicast server that is broadcasting packets. I wrote a window client that is able to capture these packets without a problem on a separate windows machine that is connected to the network. I ran into a few firewall problems on the windows machines, but worked that out.
Now, I have an ubuntu 12.04 version of the client; however, my program isn't finding these packets. I ran through all the suggestions provided by other stack overflow posts and some google threads:
when I am running my client, netstat -g shows the IP address of the multicast network
I set the rp_filter to 0 using sysctl
I can see the packets when using tcpdump -i wlan0
Added a route (sudo route add -net 224.0.0.0 netmask 224.0.0.0 wlan0)
For step four, this is a wireless connection established over wlan0, so I add the route on wlan0. Similarly, wlan0's rp_filter=0.
Now, for the code. From the print statements and error checking. I am seeing that I am successfully binding, joining the multicast group, creating the buffer, etc... Then it just blocks at the recvfrom() function call.
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <fstream>
#pragma warning( disable : 4996 )
#define MAX_PACKETSIZE 100000 // max size of packet (actual packet size is dynamic)
bool IPAddress_StringToAddr(char *szNameOrAddress, struct in_addr *Address);
void Unpack(char* pData);
#define MULTICAST_ADDRESS "239.255.42.99" // IANA, local network
#define PORT_COMMAND 1510
#define PORT_DATA 1511
#define SOCKET_ERROR -1
#define INVALID_SOCKET -1
typedef int SOCKET;
SOCKET DataSocket;
int main(int argc, char* argv[])
{
int retval;
char szMyIPAddress[128] = "";
in_addr MyAddress, MultiCastAddress;
int optval = 0x100000;
int optval_size = 4;
// client address
if(argc>1)
{
strcpy(szMyIPAddress, argv[1]); // specified on command line
IPAddress_StringToAddr(szMyIPAddress, &MyAddress);
}
else
{ printf("usage: ./client [local_ip_address]\n"); return 0; }
MultiCastAddress.s_addr = inet_addr(MULTICAST_ADDRESS);
printf("Client: %s\n", szMyIPAddress);
printf("Multicast Group: %s\n", MULTICAST_ADDRESS);
// create a "Data" socket
printf("Create Socket.\n");
DataSocket = socket(AF_INET, SOCK_DGRAM, 0);
// allow multiple clients on same machine to use address/port
int value = 1;
printf("Set SO_REUSEADDR sockopt.\n");
retval = setsockopt(DataSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&value, sizeof(value));
if (retval == SOCKET_ERROR)
{
close(DataSocket);
return -1;
}
//bind
struct sockaddr_in MySocketAddr;
memset(&MySocketAddr, 0, sizeof(MySocketAddr));
MySocketAddr.sin_family = AF_INET;
MySocketAddr.sin_port = htons(PORT_DATA);
MySocketAddr.sin_addr = MyAddress;
printf("Bind Socket.\n");
if (bind(DataSocket, (struct sockaddr *)&MySocketAddr, sizeof(struct sockaddr)) == SOCKET_ERROR)
{
printf("[PacketClient] bind failed.\n");
return 0;
}
// join multicast group
struct ip_mreq Mreq;
Mreq.imr_multiaddr = MultiCastAddress;
Mreq.imr_interface = MyAddress;
printf("Join multicast group.\n");
retval = setsockopt(DataSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&Mreq, sizeof(Mreq));
if (retval == SOCKET_ERROR)
{
printf("[PacketClient] join failed.\n");
return -1;
}
// create a 1MB buffer
printf("Create 1MB Buffer.\n");
setsockopt(DataSocket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, 4);
getsockopt(DataSocket, SOL_SOCKET, SO_RCVBUF, (char *)&optval, (socklen_t*)&optval_size);
if (optval != 0x100000)
{
printf("[PacketClient] ReceiveBuffer size = %d\n", optval);
}
//listening
printf("Listening...\n");
char szData[20000];
int addr_len = sizeof(struct sockaddr);
sockaddr_in TheirAddress;
while (1)
{
// Block until we receive a datagram from the network (from anyone including ourselves)
int nDataBytesReceived = recvfrom(DataSocket, szData, sizeof(szData), 0, (sockaddr *)&TheirAddress, (socklen_t*)&addr_len);
Unpack(szData);
}
return 0;
}
// convert ipp address string to addr
bool IPAddress_StringToAddr(char *szNameOrAddress, struct in_addr *Address)
{
int retVal;
struct sockaddr_in saGNI;
char hostName[256];
char servInfo[256];
u_short port;
port = 0;
// Set up sockaddr_in structure which is passed to the getnameinfo function
saGNI.sin_family = AF_INET;
saGNI.sin_addr.s_addr = inet_addr(szNameOrAddress);
saGNI.sin_port = htons(port);
// getnameinfo
if ((retVal = getnameinfo((sockaddr *)&saGNI, sizeof(sockaddr), hostName, 256, servInfo, 256, NI_NUMERICSERV)) != 0)
{
printf("[PacketClient] GetHostByAddr failed.\n");
return false;
}
Address->s_addr = saGNI.sin_addr.s_addr;
return true;
}
void Unpack(char* pData)
{
printf("Begin Packet\n-------\n");
}
Any suggestions are appreciated. Here is the question I used as a reference when trying to fix this problem: UDP socket (multicast) not receiving data (Ubuntu)
I paste my answer here instead writing it in comments.
As I understood you have windows machines on both sides, successfully broadcasting udp packets and now you want to replace them with ubuntu machines. And the machines are receiving the packets, but your client isn't notified.
Maybe this will help
SOL_SOCKET is for the socket layer, IPPROTO_IP for the IP layer, etc... For multicast programming, level will always be IPPROTO_IP
Here is the working code for simplified RIPv2 protocol that sends and reives multicast traffic without an problem.
int setup_sender_connection(struct in_addr interface_addr){
//create socket
int sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock<0){
die("Creating Socket");
}
//set outgoing interface
if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &interface_addr, sizeof(interface_addr))<0){
die("Setting outgoing interface");
}
//disable loopback
u_char loop = 0;
if(setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))<0){
die("Disabling loopback");
}
//allow reusing of port
int reuse = 1;
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0){
die("Allowing reuse");
}
//bind to this port
struct sockaddr_in saddr;
bzero(&saddr, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(520);
saddr.sin_addr = interface_addr;
if(bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in))<0){
die("Binding");
}
return sock;
}
void join_group(int sock, struct in_addr interface_addr){
//join gorup
struct ip_mreq mreq;
bzero(&mreq, sizeof(struct ip_mreq));
mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_IP); /* IP multicast address of group */
mreq.imr_interface = interface_addr; /* local IP address of interface */
if(setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))<0){
die("Joining group");
}
}
void die(char *error){
perror(error);
exit(1);
}

How would I go about making this udpclient asynchronous using pthreads?

How would I go about making this udpclient asynchronous using pthreads? I want to make sure UDP datagram won't be lost and also don't want the client program to wait forever and not be able to send any more messages
/*udpclient.c program */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
/* Here are some details of the sockaddr_in structure and the sockaddr structure
These declarations are copied from winsock.h
struct in_addr { this struct holds a 32 bit IP address
union {
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr
struct sockaddr_in { notice this structure is 16 bytes long
short sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr { this generic address structure is 16 bytes long, too!
u_short sa_family;
char sa_data[14];
};
*/
/* we have to send on the same port the server is listening on */
#define PORT 20009
/* simple upd client */
int main()
{
#ifdef WIN
SOCKET sock;
#else
int sock;
#endif
int size;
int nbytes, flags;
int i;
char * cp;
#ifdef WIN
WSADATA wsaData;
int nCode;
#endif
char buffer[100];
char str_addr[20]; /* holds the chars of an IP address */
struct sockaddr_in target_pc, me;
/* magic call to initialize the network I/O code - only Microsoft requires this */
#ifdef WIN
if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
printf("Opps! WSA error %d\n",nCode);
return -1;
}
#endif
/* create a socket to send on */
sock = socket(PF_INET,SOCK_DGRAM,0);
if(sock < 0) {
printf("socket error = %d\n", sock);
return -1;
}
/* we fill in the address family and port, but we do not know the destination IP address yet */
target_pc.sin_family = PF_INET;
target_pc.sin_port = htons(PORT);
/* fill in my address and port */
me.sin_family = PF_INET;
me.sin_port = htons(0);
me.sin_addr.s_addr = htonl(INADDR_ANY);
i = bind(sock, (struct sockaddr *) &me, sizeof(me));
if( i < 0) {
printf("bind result: %d\n", i);
return -1;
}
nbytes = 99;
while(1){
printf("Enter the target IP address: ");
cp = fgets(str_addr,19,stdin);
/* remove the \n */
str_addr[strlen(str_addr)-1] = '\0';
/* the inet_addr function converts a string form of IP address to a 32 binary integer */
target_pc.sin_addr.s_addr = inet_addr(&str_addr[0]);
printf("Enter your message: ");
cp = fgets(buffer,99,stdin);
/* get the string length so we send exactly this many characters */
nbytes = strlen(buffer);
flags = 0;
size = sendto(sock, (char *) buffer, nbytes,flags,(struct sockaddr *)&target_pc,sizeof(target_pc));
printf("msg size = %d size = %d\n", nbytes, size);
//added
int addrlen = sizeof(target_pc);
size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&target_pc,&addrlen);
if((size > 0) && (size < 99)){
buffer[size] = '\0'; //add the null byte so buffer now holds a string
i = puts((char *) buffer); // write this string to the display
}
}
#ifdef WIN
system("PAUSE");
#endif
return 0;
}
/udpserver.c program/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#ifdef WIN
#include <winsock.h>
#include <windows.h>
#endif
#ifndef WIN
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#endif
#define PORT 20009
/* simple upd server
this program receives short messages (<99 characters) from any IP address
and writes them to the display
be sure to use the linker line option "-l wsock32"
*/
int main()
{
/* first define a socket
a socket is an I/O port like a file descriptor
*/
#ifdef WIN
SOCKET sock; /* SOCKET is a typedef for a structure */
#else
int sock;
#endif
int size;
int nbytes, flags;
#ifdef WIN
int addrlen;
#else
socklen_t addrlen;
#endif
int i;
/* char loopback[20]="127.0.0.1"; */
#ifdef WIN
WSADATA wsaData; /* This is struct holds Windows required data */
int nCode;
#endif
char buffer[100];
struct sockaddr_in server; /* this holds my IP address and port info */
struct sockaddr_in from; /* this holds the same info for the sender of the packet
I received */
/* the call to WSAStartup is Windows magic */
#ifdef WIN
if((nCode = WSAStartup(MAKEWORD(1,1), &wsaData)) != 0){
printf("Opps! WSA error %d\n",nCode);
exit;
}
#endif
/* create a socket called sock. It is a datagram socket */
sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock < 0){
printf("socket error = %d\n", sock);
return -1;
}
server.sin_family = AF_INET; /* initialize the server address family */
server.sin_addr.s_addr = htonl(INADDR_ANY); /* notice this struct within a struct */
/* printf("%x\n",server.sin_addr.s_addr); */
server.sin_port = htons(PORT);
/* associate the socket with the address structure - this is called binding */
i = bind(sock, (struct sockaddr *) &server, sizeof(server));
if( i < 0) {
printf("bind result: %d\n", i);
return -1;
} else
printf("Simple UDP server is ready!\n\n");
nbytes = 99; /* receive packets up to 99 bytes long */
flags = 0; /* must be zero or this will not work! */
while(1){
/* the recvfrom function is a read and the arguments are:
sock - the socket we are reading
buffer - array into which to read the data
nbytes - read up to this many bytes
flags - used for special purposes - not needed here
from - sockaddr struct to hold the IP address and port of the sender of the packet
addrlen - the size of the sockaddr struct written by this function
*/
addrlen = sizeof(from);
size = recvfrom(sock, buffer, nbytes, flags, (struct sockaddr *)&from, &addrlen);
if((size > 0) && (size < 99)){
buffer[size] = '\0'; /* add the null byte so buffer now holds a string */
i = puts((char *) buffer); /* write this string to the display */
}
//echo message back to client
if(sock < 0) {//
printf("socket error = %d\n", sock);//
return -1;//
}//
sendto(sock, buffer, nbytes, flags, (struct sockaddr *)&from,addrlen); //
}
#ifdef WIN
system("PAUSE");
#endif
return 0;
}
We could create two threads: one for the sendto (that waits for the user input) and the other for recvfrom(). Next, we can have the recvrom() use Pthread condvar (by calling pthread_cond_wait() on a condvar and a Pthread mutex) and wait. When the user provides an input, we can sendto (which is not really blocking) and then call pthread_cond_signal() to wake up the other thread.
You could certainly simply this, if you wanted. If your application permits, you could completely skip the pthread_cond_wait() since recvfrom() is anyways a blocking call. So, this way, recvfrom() would block but then it would go out of sync with the send calls. The other option is to use the main() thread for the sendto() thread -- in that case, you would just need one additional thread for the recv calls.

Raw socket with device bind using setsockopt() system is not working in Fedora core 6(2.6.18-1.2798.fc6)

Please any one could help on this issue. Please
In the below sample code,we had bind raw sock with eth0. but while running the program
the recvfrom of raw sock is receiving packets from eth0 & eth1 on same machine(xx_86).
It is not clear to me why,could help one on this issue.
I hope the setsockopt is not working properly
OS: Fedora core 6(2.6.18-1.2798.fc6)
Sampe code:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/filter.h>
#include <sys/ioctl.h>
#include <string.h>
#include <arpa/inet.h>
int main(int argc, char **argv) {
int sock, i;
unsigned char buffer[2048];
unsigned char tbuff[2048];
unsigned char *iphead, *ethhead,*phead;
struct ifreq ethreq;
// NOTE: use TCPDUMP to build the filter array.
// set filter to sniff only port 443
// $ sudo tcpdump -dd port 443
// raw for recvfrom eth0
if ((sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))) == -1) {
perror("socket");
exit(1);
}
// set network card to promiscuos
strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);
if (ioctl(sock,SIOCGIFFLAGS, &ethreq) == -1) {
perror("ioctl");
close(sock);
exit(1);
}
ethreq.ifr_flags |= IFF_PROMISC;
if (ioctl(sock, SIOCSIFFLAGS, &ethreq) == -1) {
perror("ioctl");
close(sock);
exit(1);
}
//bind to sock with eth0
struct ifreq Interface;
memset(&Interface, 0, sizeof(Interface));
strncpy(Interface.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &Interface, sizeof(Interface)) < 0) { close(sock); }
//open the RAW socket for sendto
int s = socket (PF_INET, SOCK_RAW, IPPROTO_RAW);
struct sockaddr_in sin;
memset(&sin,0,sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(0);
sin.sin_addr.s_addr = inet_addr ("10.3.161.104");
// inform kernal don't fill IP and Transport header
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
printf ("Warning: Cannot set HDRINCL!\n");
//bind the sock descriptor with eth0
struct ifreq Interface1;
memset(&Interface1, 0, sizeof(Interface1));
strncpy(Interface1.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &Interface1, sizeof(Interface1)) < 0) { close(s); }
while (1) {
printf("----------------------\n");
i = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL);
printf("%d bytes read\n", i);
// check header size: Ethernet = 14, IP = 20, TCP = 8 (sum = 42)
if (i < 42) {
perror("recvfrom():");
printf("Incomplete packet (errno is %d)\n", errno);
close(sock);
exit(0);
}
phead = buffer + 14; // (skip ethernet header)
memcpy(tbuff,phead,i-14);
iphead=tbuff;
if (*iphead == 0x45) {
int ptrindex= iphead[9];
switch(ptrindex){
case 1:
printf("The transport protocl is:ICMP\n");
break;
case 2:
printf("The transport protol is:IGMP\n");
break;
case 6:
printf("The transport protocol is:TCP\n");
break;
case 17:
printf("The transport protocol is:UDP\n");
break;
case 103:
printf("The transport protocol is:PIM\n");
break;
default:
printf("The transport protocol is:%d\n",iphead[9]);
}
//printf("%d",*ptrindex);
// printf("\n The transport protocol is :%u\n",iphead[9]);
printf("Source Address: %d.%d.%d.%d, Port: %d\n",
iphead[12], iphead[13], iphead[14], iphead[15], (iphead[20] << 8) + iphead[21]);
printf("Dest Address: %d.%d.%d.%d, Port: %d\n",
iphead[16], iphead[17], iphead[18], iphead[19], (iphead[22] << 8) + iphead[23]);
if(sendto(s,tbuff,i-14,0,(struct sockaddr *)&sin,sizeof(sin))<0)
printf("error\n");
else{printf("\nThe received packet is send\n");}
memset(buffer,0,sizeof(buffer));
memset(tbuff,0,sizeof(tbuff));
}
else{ printf("The non ip had received");}
}
close(sock);
}
In the linux man page (http://linux.die.net/man/7/socket) :
SO_BINDTODEVICE
Bind this socket to a particular device like "eth0", as specified in the passed interface name. If the name is an empty string or the option length is zero, the socket device binding is removed. The passed option is a variable-length null-terminated interface name string with the maximum size of IFNAMSIZ. If a socket is bound to an interface, only packets received from that particular interface are processed by the socket. Note that this only works for some socket types, particularly AF_INET sockets. It is not supported for packet sockets (use normal bind(2) there).
So, try the bind instead.
Thanks all,thanks you very much for valuable time. it is worked with bind approach
The code segments had helped me.
setsockopt() is bug in the fedora 2.6.18
alternative approach is below.
void BindToInterface(int raw , char *device , int protocol) {
struct sockaddr_ll sll;
struct ifreq ifr; bzero(&sll , sizeof(sll));
bzero(&ifr , sizeof(ifr));
strncpy((char *)ifr.ifr_name ,device , IFNAMSIZ);
//copy device name to ifr
if((ioctl(raw , SIOCGIFINDEX , &ifr)) == -1)
{
perror("Unable to find interface index");
exit(-1);
}
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(protocol);
if((bind(raw , (struct sockaddr *)&sll , sizeof(sll))) ==-1)
{
perror("bind: ");
exit(-1);
}
return 0;
}

Resources