i try to get the mac address of an interface i want to work with.
I use this code to do so, but i get always the error message "Inappropriate ioctl for device
"
I already tried using a different socket, ie AF_INET with SOCK_DGRAM (though i need the raw socket for later usage) without any difference.
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if_ether.h>
#include <net/if.h>
int main()
{
char if_name[] = "eth0";
char mac[ETH_ALEN];
struct ifreq ifr;
int sock;
if(sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)) < 0)
{
perror("SOCKET");
return 1;
}
// get mac address of our interface
memset(&ifr, 0, sizeof(struct ifreq));
memcpy(ifr.ifr_name, if_name, 4);
if(ioctl(sock, SIOCGIFHWADDR, &ifr) == -1)
{
perror("SIOCGIFHWADDR");
return 1;
}
memcpy(mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
printf("%x.%x.%x.%x.%x.%x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
The problem should be pretty obvious if you turned on more warnings:
if(sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP)) < 0)
The above assigns the result of the comparison to sock, and of course it's not the valid socket.
Instead you need to use parentheses to avoid the operator precedence problem:
if((sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) < 0)
Related
I'm trying to create a tunnel in C and im struggling to set its IP address up. I have an "invalid argument" error in ioctl with SIOCSIFADDR argument. Can someone explain me how to set up the IP address if this function doesn't work with tun ?
#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/if_tun.h>
#include <linux/if.h>
#include <fcntl.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#define IP_DEST "127.0.0.1"
#define IP_SOURCE "127.0.0.1"
int tun_alloc(char* dev) {
//dev will store the name of the tun created
struct ifreq ifr;
int fd, err;
char *clonedev = "/dev/net/tun";
//open the clone device
if( (fd = open(clonedev, O_RDWR)) < 0 ) {
printf("Error opening directory");
return fd;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN;
if (*dev) {
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
//Create the TUN
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ) {
close(fd);
printf("Error creating the tun");
return err;
}
strcpy(dev, ifr.ifr_name);
return fd;
}
int main(int argc, char* argv[]) {
//Creating the TUN interface
char tun_name[IFNAMSIZ];
strncpy(tun_name, "tun3", IFNAMSIZ);
int tunfd = tun_alloc(tun_name);
if (tunfd < 0) {
perror("tun_create");
return 1;
}
printf("TUN interface %s created\n", tun_name);
//Setting its IP Adress
struct ifreq ifr;
struct sockaddr_in addr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, tun_name, IFNAMSIZ);
addr.sin_family = AF_INET;
if(inet_pton(AF_INET,IP_DEST,&(addr.sin_addr))<0){
fprintf(stderr,"ERROR with the IP address");
return 1;
};
memcpy(&(ifr.ifr_addr), &addr, sizeof (struct sockaddr));
if (ioctl(tunfd, SIOCSIFADDR, &ifr) < 0) {
perror("ioctl");
exit(1);
}
printf("TUN interface %s set IP address to %s\n", tun_name, IP_DEST);
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if(ioctl(tunfd, SIOCSIFFLAGS, &ifr)<0){
perror("ioctl");
exit(1);
};
printf("TUN running");
return 0;
}
I don't really understand how iotcl works and the documentation hasn't helped me for tun interfaces.
The SIOCSIFADDR and SIOCSIFFLAGS (and other SIOwhatever) ioctl calls should be made towards any AF_INET socket, not towards the tun interface itself. The design is so that you can use them to configure any interface, not only the one you created. You have to create an AF_INET socket and then call ioctl on that socket.
If you think it's a bit weird that you have to make a socket, you're right. ioctl is used to make "special requests" about files, other than read or write. The request is interpreted depending on the type of file. Using a socket makes sure it is interpreted by the IP networking system as a request relating to IP sockets. It would make logical sense that you could also make IP-related special requests on tun interfaces, but apparently the kernel developers didn't think of that, and there is no need for them to work since you can just create a socket.
There is another way to set IP addresses using a system called "rtnetlink", but it is more complicated and unnecessary for a simple scenario like this.
I am currently struggling with finding out the ip, port and transport type of a inet/inet6 socket in C.
The problem is that I got a socket fd like
int s = socket( ... );
bind(s, soa, soa_len);
Now, I got s and want to find out which Transport/Interface/Port it is bound to.
Interface and Port is easy enough via
struct sockaddr_storage sa = {};:w
getsockname(s, (struct sockaddr*) &sa, sizeof(sa));
/* parse the fields of sa depending on sa.sa_family */
However, I cannot figure out a way to find out whether s is a TCP or UDP socket - it must be somehow associated however - So:
How can I find out the transport protocol s uses?
Use the getsockopt(descriptor, SO_TYPE, ...) as described in the man 7 socket man page. For example:
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
int socket_type(const int fd)
{
int type = -1;
socklen_t typelen = sizeof type;
if (fd == -1) {
errno = EINVAL;
return -1;
}
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &typelen) == -1)
return -1;
errno = 0;
return type;
}
For TCP (AF_INET and AF_INET6 socket families), this will return SOCK_STREAM; for UDP, SOCK_DGRAM.
I have looked for a similar question, but I could not find one that would work for me. I am doing a simple project for one of my subjects, but I never had experience with sockets, so I need some help with the implementation of one feature.
Basically, there are several units interconnected by a communication network (physical ETHERNET 1Gbps, TCP / IP protocol), and I have to be able to communicate with all the boards. I can implement all other features I need on one specific board, but I don't know how to manipulate all the boards simultaneously.
So, the question is: how to get a list of all boards connected and how to select which board should receive/send a message?
Big thanks to anyone who would help.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include "mzapo_parlcd.h"
#include "mzapo_phys.h"
#include "mzapo_regs.h"
#define MY_PORT 55555
#define BUFLEN 512
int main(int argc, char *argv[])
{
int sockfd;
char buffer[BUFLEN];
struct sockaddr_in peeraddr;
// SET UP A NETWORK SOCKET
if ((sockfd = socket (AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
exit(1);
}
int broadcast = 1;
if (setsockopt (sockfd, SOL_SOCKET, SO_BROADCAST, & broadcast,
sizeof broadcast) == -1) {
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
struct sockaddr_in bindaddr;
memset(&bindaddr, 0, sizeof(bindaddr));
bindaddr.sin_family = AF_INET;
bindaddr.sin_port = htons(MY_PORT);
bindaddr.sin_addr.s_addr = INADDR_ANY;
int yes=1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(yes)) == -1) {
perror("setsockopt (SO_REUSEADDR)");
exit(1);
}
if (bind(sockfd, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) == -1) {
perror("bind");
exit(1);
}
broadcast = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast,
sizeof broadcast) == -1) {
perror("setsockopt (SO_BROADCAST)");
exit(1);
}
struct sockaddr_in braddr;
memset(&braddr, 0, sizeof(braddr));
braddr.sin_family = AF_INET;
braddr.sin_port = htons(MY_PORT );
braddr.sin_addr.s_addr = INADDR_BROADCAST;
strncpy(buffer, "Hello world", sizeof(buffer));
char* ipString = inet_ntoa(bindaddr.sin_addr);
while(1){
printf("%s", ipString);
if (sendto(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&braddr, sizeof(braddr)) == -1){
perror("sendto");
exit(1);
}
peeraddr_len = sizeof(peeraddr);
}
return 0;
}
I've been a Unix programmer for a decent amount of time, and I know pretty well the system's socket API, I use it mostly for networking.
The thing is that I'm currently trying to create a cross-platform software, and so I began to learn how to compile my source code into windows executable files.
I've created a startup() function which does the simplest thing: connect to a server (of which IP is given), and return -1 on failure. On Linux my code runs smooth, but on Windows(7) I get the same error on some machines - "Connect()" function failed, errno: "Result too large" which (by what I understood) means it could no find any listening server on that IP, but on others it runs well.
Here is the code (win version):
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <windows.h>
#include <winsock.h>
#define ADDR "127.127.127.127"
#define PORT 8752
int startup(struct sockaddr_in sin)
{
int sockfd, soaddr;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
fprintf(stderr, "WSAStartup failed.\n");
exit(1);
}
if((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
{
fprintf(stderr, "socket:%s\n", strerror(errno));
return(-1);
}
soaddr = sizeof(sin);
if(connect(sockfd, (struct sockaddr*)&sin, soaddr) == -1)
{
fprintf(stderr, "connect:%s\n", strerror(errno));
return(-1);
}
return sockfd;
}
int main(int argc, char *argv[])
{
int sockfd;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(ADDR);
sockfd = startup(sin);
// Code continues
return(0);
}
note:ADDR has been changed for privacy reasons, but there is a working server on that machine
So, why exactly am I getting this error ?
WinSock does not use errno, it uses WSAGetLastError() instead.
WinSock does not use file descriptors for sockets, it uses actual kernel objects. On Windows, you need to use the SOCKET handle type, not int, for your socket variables (or at least type-cast SOCKET values to (u)intptr_t and then type-cast back to SOCKET when calling WinSock functions).
You can use the Win32 API FormatMessage() function to get a human readable string for a WinSock error code.
#define _WIN32_WINNT 0x0501
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <windows.h>
#include <winsock.h>
#define ADDR "127.127.127.127"
#define PORT 8752
__declspec(thread) char errmsg[256];
char* sockerr(int errcode)
{
DWORD len = FormatMessageA(FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode, 0, errmsg, 255, NULL);
if (len != 0)
errmsg[len] = 0;
else
sprintf(errmsg, "error %d", errcode);
return errmsg;
}
int startup()
{
WSADATA wsaData;
int ret = WSAStartup(MAKEWORD(1,1), &wsaData);
if (ret != 0) {
fprintf(stderr, "WSAStartup:%s\n", sockerr(ret));
return(ret);
}
return(0);
}
void cleanup()
{
WSACleanup();
}
SOCKET connectToServer(struct sockaddr_in sin)
{
SOCKET sockfd;
int soaddr;
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd == INVALID_SOCKET)
{
fprintf(stderr, "socket:%s\n", sockerr(WSAGetLastError()));
return(INVALID_SOCKET);
}
soaddr = sizeof(sin);
if (connect(sockfd, (struct sockaddr*)&sin, soaddr) == -1)
{
fprintf(stderr, "connect:%s\n", sockerr(WSAGetLastError()));
closesocket(sockfd);
return(INVALID_SOCKET);
}
return(sockfd);
}
int main(int argc, char *argv[])
{
SOCKET sockfd;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(ADDR);
if (startup() != 0) {
exit(1);
}
sockfd = connectToServer(sin);
if (sockfd != INVALID_SOCKET)
{
// ...
closesocket(sockfd);
}
cleanup();
return(0);
}
You will have to take these differences into consideration when writing cross-platform socket code.
According to your code you are running client socket in windows machine.You need to load runtime libraries for windows as
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
You can refer to Windows Client Socket Source. Hope this works for you.
In linux, how can I transmit an UDP packet using 0.0.0.0 as source address.
Here is what I have tried so far.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <net/if.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
int main(int argc, const char *argv[])
{
struct sockaddr_in dst, src;
struct ifreq ifr;
int sock, tmp;
char payload[128];
memset(payload, 0, 128);
memset(&dst, 0, sizeof(dst));
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = inet_addr("255.255.255.255");
dst.sin_port = htons(67);
memset(&src,0,sizeof(src));
src.sin_family = AF_INET;
src.sin_addr.s_addr = inet_addr("0.0.0.0");
src.sin_port = htons(68);
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
perror("Failed to create socket");
tmp = 1;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &tmp, sizeof(tmp)) < 0)
perror("SO_BROADCAST failed");
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) < 0)
perror("SO_REUSEADDR failed");
if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &tmp, sizeof(tmp)) < 0)
perror("IP_FREEBIND failed");
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth1", sizeof(ifr.ifr_name));
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0)
perror("SO_BINDTODEVICE failed");
if (bind(sock, (const struct sockaddr*)&src, sizeof(struct sockaddr_in)) < 0)
perror("bind failed");
if (connect(sock, (const struct sockaddr*)&dst, sizeof(struct sockaddr_in)) < 0)
perror("bind failed");
if (write(sock, payload, 128) < 0 )
perror("Write failed");
close(sock);
return 0;
}
The problem is the the source address is only set to 0.0.0.0 if no interfaces has an IPv4 address. If just one interface has an IPv4 address, this address is used as source address.
I have looked at the source code of some of the existing DHCP clients, and found that they are using RAW sockets and building the IP and UDP header manually. This is possibility, but I would like to avoid doing this manually.
You should use RAW SOCKET and construct packet with your own efforts.
As an example you can take this: https://github.com/fycth/DHCP-server-scanner/blob/master/src/dhcpd-detector.c
This is my educational project. It is small and you can look how exactly this task is solved there.
I think if it was possible to do it via UDP sockets, they would do it instead of building one manually. So I'd suppose it doesn't work at all...