We are trying to communicate with the server listening on Linux loopback interface via raw socket and it seems like the server does not get a single packet from us. The packets we send are visible in Wireshark.
Is raw socket on loopback possible at all? (Please, don't ask why we need it: it's too complicated to explain here)
EDIT: this is how we open it
_I_RawSocket = socket( PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))
memset( &ifr, 0, sizeof( ifr ) );
strcpy( ifr.ifr_ifrn.ifrn_name, _InterfaceName);
ioctl( _I_RawSocket, SIOCGIFINDEX, &ifr )
memset( &sll, 0, sizeof( sll ) );
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons( ETH_P_ALL );
bind( _I_RawSocket, (struct sockaddr *) &sll, sizeof( sll ))
The server is lighttpd and it's reachable via normal socket on localhost.
netstat --raw prints empty table but I'm absolutely sure we have two functional raw sockets on normal eth devices.
Raw sockets behave particularly fizzy with bind() and connect(), but I can't confirm that your issue lies with them. I suggest you follow a more straightforward approach:
Sender
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#define DEST "127.0.0.1"
int main(int argc, char **argv)
{
int s;
struct sockaddr_in dst_addr;
char packet[50];
struct iphdr *ip = (struct iphdr *)packet;
if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
dst_addr.sin_family = AF_INET;
dst_addr.sin_port = 0; /* not needed in SOCK_RAW */
inet_pton(AF_INET, DEST, (struct in_addr *)&dst_addr.sin_addr.s_addr);
memset(dst_addr.sin_zero, 0, sizeof(dst_addr.sin_zero));
memset(packet, 'A', sizeof(packet)); /* payload will be all As */
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = htons(40);
ip->frag_off = 0; /* NF */
ip->ttl = 64;
ip->protocol = IPPROTO_RAW; /* this has to be IPPROTO_RAW */
ip->check = 0;
ip->saddr = dst_addr.sin_addr.s_addr;
ip->daddr = dst_addr.sin_addr.s_addr;
while(42) {
sleep(5);
if (sendto(s, packet, sizeof(packet), 0,
(struct sockaddr *)&dst_addr, (socklen_t)sizeof(dst_addr)) < 0)
perror("uh oh:");
}
return(0);
}
Receiver
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int s;
struct sockaddr_in src_addr;
char packet[50];
if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("error:");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(packet));
socklen_t *len = (socklen_t *)sizeof(src_addr);
int fromlen = sizeof(src_addr);
while(42) {
if (recvfrom(s, &packet, sizeof(packet), 0,
(struct sockaddr *)&src_addr, &fromlen) < 0)
perror("uh oh:");
int i = sizeof(struct iphdr); /* print the payload */
for(; i < sizeof(packet); i++) {
printf("%c", packet[i]);
}
printf("\n");
}
return(0);
}
I hope these behave exactly like you want them to. Read man 7 raw for the gory details of why this works and more importantly man 7 packet if you want to extend it. Also, take note that IPPROTO_RAW implies the IP_HDRINCL socket option, which is why we're constructing the ip header ourselves - although the IP checksum and total length are computed and filled in by the kernel, still.
edit: In addition, if you wanted a raw socket with which to send valid data to an application like lighttpd, you'd have to match the protocol argument to socket() as well as provide valid values for the IP header fields. A proper ethernet header is not mandatory - the only important field will be filled for you by the kernel stack.
Please make sure bind to if_index
if (ioctl(sock, SIOCGIFINDEX, &stEthReq ) < 0 )
{
printf( "failed to get IF index!" );
return -1;
}
memset(&client_addr, 0, sizeof(client_addr));
client_addr.sll_family = AF_PACKET;
client_addr.sll_ifindex = stEthReq.ifr_ifru.ifru_ivalue;
client_addr.sll_protocol = VOS_HTONS(usEthType);
ret = bind(sock,(struct sockaddr *)(&client_addr), sizeof(client_addr));
Related
I am doing some testing with Unix domain sockets and I can communicate over them without an issue, however, when I call accept() on the server side of my test program, the returned struct sockaddr_un doesn't contain a sun_path.
I am pretty sure that Inet sockets have their address and port properly filled out after an accept() call, so am I doing something wrong in my test program or am I expecting the wrong outcome?
I am running CentOS 6.2 and gcc 4.4.6.
Sample Code:
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NAME "socket"
int main(int argc, char **argv)
{
int sock, msgsock, rval;
struct sockaddr_un server, client;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
for (;;) {
socklen_t len = sizeof(client);
msgsock = accept(sock, (struct sockaddr *)&client, &len);
if (msgsock == -1)
perror("accept");
else do {
printf("strlen(sun_path) = %zu\n", strlen(client.sun_path));
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
return 0;
}
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DATA "Half a league, half a league . . ."
int main(int argc, char **argv)
{
int sock;
struct sockaddr_un server;
if (argc < 2) {
printf("usage:%s <pathname>", argv[0]);
exit(1);
}
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[1]);
if (connect(sock, (struct sockaddr *) &server,
sizeof(struct sockaddr_un)) < 0) {
close(sock);
perror("connecting stream socket");
exit(1);
}
if (write(sock, DATA, sizeof(DATA)) < 0)
perror("writing on stream socket");
close(sock);
return 0;
}
Just to reiterate the question:
Why isn't sun_path filled out after the accept() call on the server?
I am really not sure if this is an answer at all. Probably it's more like musings about some research, though maybe still worth while reading.
The value filled by accept(2) seems to be quite protocol agnostic at least in Linux 3.16.0, NetBSD 6.1.4 and Darwin 13.1.0 kernels. In practice this means that the second parameter to accept(2), struct sockaddr * gets filled only up to what is shared between all protocols. So what you have in your hands after a successful acccept(2) is far from being a complete struct sockaddr_un.
Probably nobody thought it would be of much importance at the time first implementations of accept(2) were done and now we're stuck with this. Fortunately there is a way around that, in case one has lost the pathname used for socket with call to bind(2), and would now like to find it again.
With struct sockaddr_storage and getsockname(2) the member sun_path is accessible. So, to make sure you are getting all juicy details, call getsockname(2) after a successful call to accept(2) (this would be put after line number 40 in your server.c):
struct sockaddr_storage ss;
socklen_t sslen = sizeof(struct sockaddr_storage);
if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
printf("socket name is: %s\n", un->sun_path);
}
Or just use this:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NAME "socket"
int main(int argc, char **argv)
{
int sock, msgsock, rval;
struct sockaddr_un server, client;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
for (;;) {
socklen_t len = sizeof(client);
msgsock = accept(sock, (struct sockaddr *)&client, &len);
if (msgsock == -1)
perror("accept");
else do {
printf("strlen(sun_path) = %zu\n", strlen(client.sun_path));
struct sockaddr_storage ss;
socklen_t sslen = sizeof(struct sockaddr_storage);
if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
printf("socket name is: %s\n", un->sun_path);
}
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
return 0;
}
This has been tested, ie. it compiles and produces expected results, to work on a GNU/Linux system running kernel 3.16.0, a NetBSD system running 6.1.4 kernel, and a system equipped with OS/X Mavericks, running 13.1.0 kernel. In all of these behaviour of accept(2) is consistent: sun_path is nowhere to be found in the structure filled. The behaviour of getsockname(2) is consistent between different operating environments too, making all protocol specific details available.
You haven't bound your client socket to an address.
You don't need to bind your client socket to an address for connect() to work; but, if you expect to access your client address in your server, then you do have to bind().
Make sense?
Just setup a call to bind() before you connect in your client. Make sure you the path you use for you client is valid and check for errors as normal.
What is the best possible way to send packets coming on an interface back to the same interface without changing anything in the packet. I want to have a loopback effect for the actual traffic coming on one of my interfaces e.g eth0
I think you can easily achieve this with Python/Scapy. Something like
sniff(iface="eth0", prn=lambda x: sendp(x, iface="eth0"))
should do it.
I don't think you can do this easily with a physical interface. I used the tap module for this purpose, though. It's quite simple: I create a new tap interface, and my program writes back everything that is read from the device. I used this to test a proprietary network protocol - so it might or might not work for what you intend to do. The code is quite simple:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_tun.h>
#define DEVNAME "gnlo0"
static int tun_alloc(char *dev)
{
struct ifreq ifr;
int fd, ret;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
perror("open");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP;
if (*dev)
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
ret = ioctl(fd, TUNSETIFF, (void *)&ifr);
if (ret < 0) {
close(fd);
perror("ioctl TUNSETIFF");
return ret;
}
strcpy(dev, ifr.ifr_name);
return fd;
}
int main(int argc, char **argv)
{
int fd = -1;
int ret = 1;
char dev[IFNAMSIZ];
strncpy(dev, DEVNAME, IFNAMSIZ - 1);
printf("opening %s\n", dev);
fd = tun_alloc(dev);
if (fd < 0)
goto out;
char buf[512];
snprintf(buf, sizeof(buf) - 1,
"ip addr flush dev %s; ip link set dev %s up", dev, dev);
if (system(buf) < 0) {
perror("system");
goto out;
}
while (1) {
unsigned char packet[65535];
int len = read(fd, packet, sizeof(packet));
if (len < 0) {
perror("read");
goto out;
}
printf("incoming packet [%d octets]\n", len);
len = write(fd, packet, len);
printf("fed back packet [%d octets]\n", len);
}
ret = 0;
out:
if (fd >= 0)
close(fd);
return ret;
}
I have had a rather strange observation about behavior of setsockopt on Linux for SO_REUSEADDR. In one line: if I apply the sockopt to an fd returned by accept on a "listening socket" the socketoption is reflected on the port held by the listening socket.
Ok some code.
Server : Opens a socket, applies SO_REUSEADDR to be true. Accepts a connection and then applies SO_REUSEADDR to be false on the fd on the fd returned by accept.
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
int main(void)
{
int s, len;
int sin_size;
int reuse = 1;
int ret;
struct sockaddr_in my_addr;
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
my_addr.sin_port = htons(33235);
if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Socket Error\n");
return -1;
}
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
if( bind(s, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) < 0)
{
printf("Bind Error\n");
return -1;
}
listen(s, 6);
reuse = 0;
memset(&my_addr, 0, sizeof(my_addr));
while(1) {
ret = accept(s, (struct sockaddr*)&my_addr, &len);
if (ret<0) {
printf("Accept failed\n");
} else {
printf("Accepted a client setting reuse add to 0\n");
setsockopt(ret, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int));
}
}
printf("Server exiting\n");
return 0;
}
Client : Client connects to the server, and doesn't do anything after that ensuring that the server socket stays in TIME_WAIT state.
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
int main(void)
{
int s, len;
int sin_size;
struct sockaddr_in my_addr;
memset(&my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
my_addr.sin_port = htons(33235);
if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Socket Error\n");
return -1;
}
if (!connect(s,(struct sockaddr*)&my_addr, sizeof(struct sockaddr)))
{
printf("Client Connected successfully\n");
}
else
{
printf("%s\n",strerror(errno));
}
while(1) sleep(1);
return 0;
}
Steps that I do reproduce the issue.
Run server.
Connect client.
Kill and restart server. The server fails with Bind Failure
I tested this on mac os. And the bind didn't fail. I have digged up all Posix specifications and none of them say that this code is undefined.
Question:
Can someone with more experience on this share their understanding of the issue?
One way to think about it is that SO_REUSEADDR determines if you can have another socket bound to that same address. It's a property of any socket (listen or connection), but very commonly inherited from listen via accept. In linux it's mapped to the struct sock "sk_reuse" flag.
If you clear this flag on a FD you "accepted" then from that point on the IP/Port pair is considered busy-and-non-reusable. The SO_REUSEADDR flag on the listen socket does not change, but the flag on the accepted socket affects bind logic. You could probably check this with getsockopt.
If you want to know more you can try to read the inet_csk_get_port function: http://lxr.free-electrons.com/source/net/ipv4/inet_connection_sock.c#L100. This is where the actual "binding" takes place.
I have the following code with connects to Redis running locally on port 6379. The problem is that can't read any output, the reader thread just blocks on recvfrom(). Everything works fine with an echo server for example, but not with Redis.
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
struct sockaddr_in servAddr;
int sock;
/* Reader loop */
void *readerf(void *n) {
char buffer[128];
int bytesRcvd;
while((bytesRcvd = recvfrom(sock, buffer, 127, 0, NULL, 0)) > 0) {
printf("[%s]",buffer);
}
}
char *getk = "GET key\n";
char *setk = "SET key \"test\"\n";
void sendd(char *str) {
if (send(sock, str, strlen(str), 0) != strlen(str))
perror("Send error");
send(sock, "\0", 1, 0);
//printf("sent: [%s]",str);
}
int main(int argc, char *argv[]) {
int i = 1;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
return 1;
/* Construct the server address structure */
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family */
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); /* Server IP address */
servAddr.sin_port = htons(6379); /* Server port */
if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr))<0)
perror("Could not connect");
sendd(getk);
sendd(setk);
sendd(getk);
pthread_t reader;
pthread_create(&reader, NULL, readerf, &i);
sleep(5);
close(sock);
return 0;
}
It seems like you are not properly implementing Redis' protocol: http://redis.io/topics/protocol
If you are seriously coding a client, and not just investigating/having fun consider hiredis: https://github.com/antirez/hiredis/
How to UDP Broadcast with C in Linux?
In many IP stack, such as Linux, this code does not work. Your socket must have broadcast permissions. Try this:
bcast_sock = socket(AF_INET, SOCK_DGRAM, 0);
int broadcastEnable=1;
int ret=setsockopt(bcast_sock, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
/* Add other code, sockaddr, sendto() etc. */
Unwind has it right, except you should use 'sendto'
Here is an example, that assumes you already have a socket. It was taken from clamav
static void
broadcast(const char *mess)
{
#define BROADCAST_PORT 30000u
struct sockaddr_in s;
int broadcastSock = socket(AF_INET, SOCK_DGRAM, 0);
if(broadcastSock < 0)
return;
memset(&s, '\0', sizeof(struct sockaddr_in));
s.sin_family = AF_INET;
s.sin_port = htons(BROADCAST_PORT)
s.sin_addr.s_addr = INADDR_BROADCAST; /* This is not correct : htonl(INADDR_BROADCAST); */
cli_dbgmsg("broadcast %s to %d\n", mess, broadcastSock);
if(sendto(broadcastSock, mess, strlen(mess), 0, (struct sockaddr *)&s, sizeof(struct sockaddr_in)) < 0)
perror("sendto");
}
Typically using the Berkeley sockets API, to sendto() one or more datagrams to a known broadcast-class IP address.
I wrote udp multicast server recently for testing. To subscribe to multicast you would subscribe your client to Multicast group 225.0.0.37 port 12346 and port 12345 (2 feeds - one feeds sends "Hello, World!" the other one "Bye, Office!").
I've been using it for testing my client, both client and server run on the same box so there might be bits that may not work but give it a try first.
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#define BYE_OFFICE 12346
#define HELLO_PORT 12345
#define HELLO_GROUP "225.0.0.37"
int main(int argc, char *argv[])
{
struct sockaddr_in addr;
struct sockaddr_in addr2;
int fd;
int fd2;
char *message = "Hello, World!";
char *message2 = "Bye, Office!";
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
if ((fd2 = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(1);
}
/* set up destination address */
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(HELLO_GROUP);
addr.sin_port=htons(HELLO_PORT);
memset(&addr2,0,sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = inet_addr(HELLO_GROUP);
addr2.sin_port=htons(BYE_OFFICE);
while (1)
{
if (sendto(fd, message, strlen(message), 0,(struct sockaddr *) &addr, sizeof(addr)) < 0)
{
perror("sendto");
exit(1);
}
sleep(3);
if (sendto(fd2, message2, strlen(message2), 0,(struct sockaddr *) &addr2, sizeof(addr2)) < 0)
{
perror("sendto2");
exit(1);
}
sleep(3);
}
}