I have an existing tap device (tap0) that I created on command line.
# ip tuntap add dev tap0 mode tap
I want to read any data coming in on that interface using a C program. I checked other SO questions, but found code that create an interface by opening /dev/net/tun.
Can anyone provide some direction on how to open and read existing interface ? I'm not sure which file I should open for tap0 ?
Open the existing tun/tap interface similar way than creating a new one.
Just give name for the interface when ioctl(TUNSETIFF) is used:
const int fd = open("/dev/net/tun", O_RDWR);
if (fd != -1)
{
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_name, "tun0", IFNAMSIZ); // <<<<=== THIS WAY
if (ioctl(fd, TUNSETIFF, &ifr) != -1)
{
Without the strncpy line, the code creates a new interface with some free number.
With the line, it tries to open tun0. Note: it fails if the tun0 is already opened by some other process.
Above is tested with IFF_TUN. I haven't tried IFF_TAP.
You can use the file descriptor (fd) for reading and writing:
Example for tun:
char buffer[0x1000];
const int len = read(fd, buffer, sizeof(buffer));
if (len > 0)
{
static const char IPV6_VER_MASK = 0x60;
if ((buffer[0] & IPV6_VER_MASK) == IPV6_VER_MASK)
{
handle_ipv6_packet((const struct ip6_hdr*)buffer, len);
}
}
You can implement like a tcpdump to capture packets, can use libpcap or
use socket RAW_SOCKET
sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)
Of course you can also add the bpf filter
setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, ...
simple sample:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/ether.h>
#include <linux/if_packet.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int n;
int ret = 0;
int sock;
char buf[2048];
struct ifreq ifreq;
struct sockaddr_ll saddr;
// create socket
if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) {
ret = errno;
goto error_exit;
}
// bind tap0
snprintf(ifreq.ifr_name, sizeof(ifreq.ifr_name), "tap0");
if (ioctl(sock, SIOCGIFINDEX, &ifreq)) {
ret = errno;
goto error_exit;
}
memset(&saddr, 0, sizeof(saddr));
saddr.sll_family = AF_PACKET;
saddr.sll_protocol = htons(ETH_P_ALL);
saddr.sll_ifindex = ifreq.ifr_ifindex;
saddr.sll_pkttype = PACKET_HOST;
if(bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
ret = errno;
goto error_exit;
}
// recv data
while(1) {
n = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
printf("%d bytes recieved\n", n);
}
error_exit:
if (ret) {
printf("error: %s (%d)\n", strerror(ret), ret);
}
close(sock);
return ret;
}
Related
So here is the code, code successfully compiles...
#include <stdio.h> // for printf
#include <linux/if_tun.h> //for IFF_TUN
#include <sys/socket.h> //socket, struct sockaddr_in
#include <fcntl.h> // for O_RDWR macros
#include <string.h> //for strcpy
#include <unistd.h> //for read();
#include <netdb.h> //for struct sockaddr
#include <net/if.h> //struct ifreq and IFNAMSIZ and other macros
#include <errno.h>
#include <stdlib.h>
// _check: error handler
static int _check(int retval, const char *msg)
{
if(retval == -1)
{
fprintf(stderr, "%s: %s\n", msg, strerror(errno));
exit(EXIT_FAILURE);
}
return retval;
}
int tcp_listen_sock(int listen_connection)
{
/*-------------------------socket-----------------------*/
int sock, tcp_sock;
struct addrinfo hints, *result;
struct sockaddr *addrin;
memset(&hints ,0 , sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
const char *host;
host = "0.0.0.0";
_check(getaddrinfo(host, NULL, &hints, &result), "getaddrinfo");
if (result->ai_family == AF_INET)
((struct sockaddr_in *)result->ai_addr)->sin_port = htons(5678);
else if (result->ai_family == AF_INET6)
((struct sockaddr_in6 *)result->ai_addr)->sin6_port = htons(5678);
else {
fprintf(stderr, "unknown ai_family %d", result->ai_family);
freeaddrinfo(result);
return -1;
}
memcpy(addrin, result->ai_addr, result->ai_addrlen);
// *client_len = result->ai_addrlen;
_check((sock = socket(AF_INET, SOCK_STREAM, 0)), "socket");
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "enp0s3");
_check(setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)), "setsockopt");
int flags;
if((flags = fcntl(sock, F_GETFL)) != -1)
{
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
}
else
perror("socket fcntl");
_check(bind(sock,result->ai_addr, result->ai_addrlen), "tcp bind");
int len = sizeof(struct sockaddr);
_check(listen(sock, listen_connection), "listen");
tcp_sock = accept(sock, result->ai_addr, &result->ai_addrlen );
printf("now listening on tcp!\n");
return tcp_sock;
}
int main(int argc, char **argv)
{
printf("Starting program\n");
int tcp = tcp_listen_sock(5);
printf("ending program\n");
return 0;
}
and ,
OUTPUT
Starting program
now listening on tcp!
ending program
but server socket is not actually listening...
expected output:
Starting program
now listening on tcp!
read...
write...
read...
write...
read...
write..
I can't figure our what I am missing, I know I didn't implemented read, write yet but I will do it after when server socket seems to working fine and listening properly.
NOTE: I am doing this in linux (specifically ubuntu)
Any help will be appreciated...
Calling getaddrinfo to initialize a local list socket seems like overkill.
Start with this. This is a simple "create a listen socket and wait for an incoming TCP connection" code sample.
int tcp_socket_listen(int listen_connection)
{
struct sockaddr_in addr = {0};
sockaddr_in addrRemote = {0};
socklen_t sizeRemote = 0;
int tcp_socket = -1;
s = socket(AF_INET, SOCK_STREAM, 0);
_check(s, "socket");
addr.sin_family = AF_INET;
addr.sin_port = htons(5678);
_check(bind(s, (sockaddr*)&addr, sizeof(addr)), "bind");
_check(listen(sock, listen_connection), "listen");
sizeRemote = sizeof(addrRemote);
tcp_sock = accept(s, (sockaddr*)&addrRemote, &sizeRemote);
_check(tcp_sock, "accept");
printf("now listening on TCP\n");
return tcp_sock;
}
Now if you want to bind to a specific adapter (e.g. "enp0s3") instead of the default ("all adapters") or need IPV6 support, you can peruse my sample code on github here for the GetSocketAddressForAdapter and use that address for the bind call instead of the default addr address above. It's C++, but you can probably port it to straight C with a little work.
I am trying to read from a socketCAN and the msg is always filtered for the 11bit identifier.
This should be a problem fixable with setting the rpoper flags for the 29bit identifier but I can`t find where if anyone can help...
struct can_frame message;
struct sockaddr_can addr;
struct ifreq ifr;
int fd = -1; // file descriptor (it´s a socket)
if((fd = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
LE_INFO("cannot open socket");
return;
}
strcpy(ifr.ifr_name, "can0");
ioctl(fd, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
printf("cannot bind socket\n");
return;
}
uint8_t nbytes;
message.can_id |= CAN_EFF_FLAG;
while(1)
{
nbytes = read(fd, &message, sizeof(struct can_frame));
if (nbytes < 0) {
perror("can raw socket read");
return;
}
/* paranoid check ... */
if (nbytes < sizeof(struct can_frame)) {
fprintf(stderr, "read: incomplete CAN frame\n");
return;
}
printf("READ COB_ID:%x\n",message.can_id | CAN_EFF_FLAG);
}
return;
I am sending a CAN frame with idx x901 and this is what is printed:
READ COB_ID:80000101
READ COB_ID:80000101
READ COB_ID:80000101
I have troubleshooted this in many different ways and it seems that the C code is working as it should, but I suspect the problem to be with the kernel module for either mcp251x which is not correctly receiving the extended flag? Or it may be with some initialization I need to do before running the kernel module???
Thank you in advance to anyone who can help.
Your understanding of CAN flags and filtering is not correct. Take a look at extract from linux can.h:
/* special address description flags for the CAN_ID */
#define CAN_EFF_FLAG 0x80000000U /* EFF/SFF is set in the MSB */
#define CAN_RTR_FLAG 0x40000000U /* remote transmission request */
#define CAN_ERR_FLAG 0x20000000U /* error message frame */
/* valid bits in CAN ID for frame formats */
#define CAN_SFF_MASK 0x000007FFU /* standard frame format (SFF) */
#define CAN_EFF_MASK 0x1FFFFFFFU /* extended frame format (EFF) */
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
Here is an example that works for both SFF and EFF messages:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
int main(int argc, char **argv)
{
struct can_frame message;
struct sockaddr_can addr;
struct ifreq ifr;
int fd = -1; // file descriptor (it´s a socket)
if((fd = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
printf("cannot open socket");
return -9;
}
strcpy(ifr.ifr_name, "vcan0");
ioctl(fd, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
printf("cannot bind socket\n");
return -1;
}
u_int8_t nbytes;
message.can_id |= CAN_EFF_FLAG | CAN_RTR_FLAG | CAN_EFF_MASK;
while(1)
{
nbytes = read(fd, &message, sizeof(struct can_frame));
if (nbytes < 0) {
perror("can raw socket read");
return -2;
}
/* paranoid check ... */
if (nbytes < sizeof(struct can_frame)) {
fprintf(stderr, "read: incomplete CAN frame\n");
return -3;
}
printf("READ COB_ID: %x\n", message.can_id & CAN_EFF_MASK);
}
return 0;
}
Now sending these messages:
cansend vcan0 00000123#FFFFFFFFFFFFFFFF
cansend vcan0 12345678#FFFFFFFFFFFFFFFF
gives correct output:
READ COB_ID: 123
READ COB_ID: 12345678
I am getting this error when trying to make an application to connect and listen to a port for data.
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
int main(int argc, char * arg[]){
int conn_s = socket(AF_INET, SOCK_STREAM, 0); //Create the socket
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(1234);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
int res = bind(conn_s, (struct sockaddr *) &servaddr, sizeof(servaddr));
if(res < 0){
printf("Error has occured\n");
}
FILE * stream = fdopen(conn_s, "w+"); //Create a stream for the socket
FILE * file = fopen("response2.txt", "w+"); //Create a file to store the output of the stream
char * line = NULL; //Where each line of the stream will be stored in
size_t len = 0; // The length of the line
ssize_t bytes; //The size of the line in bytes
int lis = listen(conn_s, SOMAXCONN);
fcntl(lis, F_SETFL, O_NONBLOCK);
while(1) {
conn_s = accept(lis, NULL, NULL);
if(conn_s < 0){
if((errno == EAGAIN) || (errno == EWOULDBLOCK))
continue;
perror("Failed to accept connection");
exit(EXIT_FAILURE);
}
long conn_s_flags = fcntl(conn_s, F_GETFL);
fcntl(conn_s, F_SETFL, conn_s_flags & ~O_NONBLOCK);
while((bytes = getline(&line, &len, stream)) != -1) {
printf("%s\n", line);
fwrite(line, sizeof(char), bytes, file);
}
close(conn_s);
}
free(line);
return 0;
}
I am trying to connect to port 1234, listen to it and accept it to recieve data, but the error keeps occuring.
Also I am trying to test using netcat, but get a different error whenever nc is running on the port I specified.
Thanks
int lis = listen(conn_s, SOMAXCONN);
fcntl(lis, F_SETFL, O_NONBLOCK);
while(1) {
conn_s = accept(lis, NULL, NULL);
listen() does not return a socket FD. It returns zero or -1. The second line is therefore erroneous, as is the following accept() call. It should be:
if (listen(conn_s, SOMAXCONN) == -1)
{
perror("listen");
return; // or whatever
}
fcntl(conn_s, F_SETFL, O_NONBLOCK);
while(1) {
int conn_c = accept(conn_s, NULL, NULL);
NB Don't lose conn_s by storing the result of accept() into it.
I had to implement a application health check mechanism , I used non blocking socket with select although I achieved success
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
int connect_tout(char * hostname1, int port, int timeoutval)
{
char *hostname = hostname1; /* pointer to name of server */
struct sockaddr_in saddr; /* socket address */
int s, i;
fd_set fd_r, fd_w;
struct timeval timeout;
int flags;
timeout.tv_sec = timeoutval;
timeout.tv_usec = 0;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
saddr.sin_addr.s_addr = inet_addr(hostname1);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
/* set the socket fd to non-blocking mode */
fcntl(s, F_SETFL, (flags = fcntl(s, F_GETFL)) | O_NONBLOCK);
connect(s, (struct sockaddr *)&saddr, sizeof(saddr));
FD_ZERO(&fd_r);
FD_ZERO(&fd_w);
FD_SET(s, &fd_r);
FD_SET(s, &fd_w);
/* timeout durring connect() ?? */
select(s+1, &fd_r, &fd_w, NULL, &timeout);
if(FD_ISSET(s, &fd_w))
{
printf("ALIVE\n");
}
else
{
printf("Conect TIMEOUT \n");
close(s);
return errno;
}
i = connect(s, (struct sockaddr *)&saddr, sizeof(saddr));
if(i)
{
printf("Conect failed errno:%d\n",errno);
perror("connect:");
close(s);
return errno;
}
else
{
printf("Connect passed and OK \n");
close(s);
return 1;
}
close(s);
return 1;
}
int main (int argc, char *argv[])
{
int ret;
if (argc < 3)
{
printf("Usage: %s [host] [port] [timout]\n", argv[0]);
exit(1);
}
char *hostname = argv[1]; /* pointer to name of server <IP address>*/
connect_tout(hostname, atoi(argv[2]), atoi(argv[3]));
return 0;
}
BUT my problem comes when my code running machine goes under very high fd usage . NOTE: Opening many fds at a time at my system is common behaviour . then this piece fails each time
if(FD_ISSET(s, &fd_w))
{
printf("ALIVE\n");
}
else
{
close(s);
return errno;
printf("Conect TIMEOUT\n");
}
As I said in such environment it fails by saying TIMEOUT , I want to know why select is failing by not determining ready discripters so soon and that is each time. Is FD_ISSET() may also fall under doubt ?
P S : This runs well when system is under normal number of fds . Sorry for bad program I just pasted here my sample working code. I will check for errors later
For non-blocking connect() usage, you do not call it again after getting writeable notification. Instead, you should check the error status of the socket with getsockopt() with the SO_ERROR option.
You are not checking the return values of any of your calls, and this makes it impossible for your code to actually determine any failures correctly. Note that you do not check the case if the passed in timeout itself is 0, which would cause select() to return immediately with the instantaneous status of the socket. Note that checking for readable notification of the connecting socket is not documented by the socket API.
int s = socket(PF_INET, SOCK_STREAM, 0);
assert(!(s < 0));
int r = fcntl(s, F_SETFL, fcntl(s, F_GETFL, 0)|O_NONBLOCK);
assert(r == 0);
r = connect(s, (struct sockaddr *)&saddr, sizeof(saddr));
if (r < 0) {
if (errno == EINPROGRESS) {
FD_ZERO(&fd_w);
FD_SET(s, &fd_w);
r = select(s+1, NULL, &fd_w, NULL, NULL);
if (r < 0) {
perror("select");
abort();
}
assert(r == 1);
assert(FD_ISSET(s, &fd_w));
int erropt = -1;
socklen_t errlen = sizeof(erropt);
r = getsockopt(s, SOL_SOCKET, SO_ERROR, &erropt, &errlen);
assert(r == 0);
if (erropt != 0) {
errno = erropt;
perror("connect[after select]");
abort();
}
/* connect succeeded asynchronously */
} else {
perror("connect[direct call]");
abort();
}
} else {
/* connect succeeded synchronously */
}
I've written a simple echo server, which includes the following line:
int yes = 1;
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
However despite this, I'm still getting an error when I try to call bind on a socket I've recently used. In fact, I'm getting this error if I try to call bind on a socket I've used in this program, period, even if it's not recent - like they're not being cleared by the kernel or something. Is there something else I have to do?
Here's the full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
void prepareHints(struct addrinfo *hints, int tcp_udp) {
memset(hints, 0, sizeof(struct addrinfo));
hints->ai_family = AF_UNSPEC;
hints->ai_socktype = (tcp_udp == 1) ? SOCK_STREAM : SOCK_DGRAM;
hints->ai_flags = AI_PASSIVE; /* autofill IP */
}
void writeSocket(int fd, const char *msg) {
size_t nbytes = 0;
size_t len = strlen(msg);
while (nbytes < len)
nbytes += send(fd, msg, len, 0);
}
void waitLoop(int sockfd) {
int clientfd, nbytes;
struct sockaddr addr;
socklen_t len;
char buf[512];
while(1) {
clientfd = accept(sockfd, &addr, &len);
if (clientfd < 0) {
perror("accept");
exit(1);
}
while ((nbytes = recv(clientfd, buf, 512, 0)) != EOF) {
buf[nbytes] = '\0';
strcat(buf, "\r\n");
writeSocket(clientfd, buf);
}
close(clientfd);
}
}
int main(int argc, char **argv) {
const char *port = (argc >= 2) ? argv[1] : "7474";
struct addrinfo hints, *res;
prepareHints(&hints, 1);
int status = getaddrinfo(NULL, port, &hints, &res);
if (status != 0) {
printf("Error on getaddrinfo\n");
exit(1);
}
/* scan through sockaddr's returned by getaddrinfo until we successfully set up a socket with one */
int socketfd;
struct addrinfo *cur;
for (cur = res; cur != NULL; cur = cur->ai_next) {
if ((socketfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) >= 0)
break;
}
/* make sure we actually found one */
if (socketfd == -1) {
printf("Error on socket\n");
exit(1);
}
/* bind the socket to the struct sockaddr_in contained in res */
int bindres = bind(socketfd, cur->ai_addr, cur->ai_addrlen);
if (bindres != 0) {
perror("bind");
exit(1);
}
int yes = 1;
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (listen(socketfd, 5) < 0) {
printf("error on listen\n");
exit(1);
}
printf("success, listening on socket %d, port %d\n", socketfd, ntohs(((struct sockaddr_in *)res->ai_addr)->sin_port));
waitLoop(socketfd);
return 0;
}
You are setting SO_REUSEADDR after calling bind(). You need to set it before binding, not after.
You are getting an error on bind() and you are setting SO_REUSEADDR afterwards. It therefore has no effect.
The short version is that the kernel keeps it around because there's a period of time in which it can't tell if the packets it is getting are for the old program or the new program. It's always safest to wait. That said, my understanding is with modern networks, the chances of old packets coming in a minute late is very small.
The really short version is that it's a feature (at least it used to be) not a bug.