Related
How to find the interface used by a connected socket.So that i can set status codes for different interfaces.I used the below code.But I didnt get it.
I've tried two different approaches in the test code below, but both fail. The first one connects to a remote server, and uses ioctl with SIOCGIFNAME, but this fails with 'no such device'. The second one instead uses getsockopt with SO_BINDTODEVICE, but this again fails (it sets the name length to 0).
Any ideas on why these are failing, or how to get the I/F name? after compiling, run the test code as test "a.b.c.d", where a.b.c.d is any IPV4 address which is listening on port 80. Note that I've compiled this on Centos 7, which doesn't appear to have IFNAMSZ in <net/if.h>, so you may have to comment out the #define IFNAMSZ line to get this to compile on other systems.
Thanks.
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
int main(int argc, char **argv) {
int sock;
struct sockaddr_in dst_sin;
struct in_addr haddr;
if(argc != 2)
return 1;
if(inet_aton(argv[1], &haddr) == 0) {
printf("'%s' is not a valid IP address\n", argv[1]);
return 1;
}
dst_sin.sin_family = AF_INET;
dst_sin.sin_port = htons(80);
dst_sin.sin_addr = haddr;
if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return 1;
}
if(connect(sock, (struct sockaddr*)&dst_sin, sizeof(dst_sin)) < 0) {
perror("connect");
return 1;
}
printf("connected to %s:%d\n",
inet_ntoa(dst_sin.sin_addr), ntohs(dst_sin.sin_port));
#if 0 // ioctl fails with 'no such device'
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
// get the socket's interface index into ifreq.ifr_ifindex
if(ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
return 1;
}
// get the I/F name for ifreq.ifr_ifindex
if(ioctl(sock, SIOCGIFNAME, &ifr) < 0) {
perror("SIOCGIFNAME");
return 1;
}
printf("I/F is on '%s'\n", ifr.ifr_name);
#else // only works on Linux 3.8+
#define IFNAMSZ IFNAMSIZ // Centos7 bug in if.h??
char optval[IFNAMSZ] = {0};
socklen_t optlen = IFNAMSZ;
if(getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &optval, &optlen) < 0) {
perror("getsockopt");
return 1;
}
if(!optlen) {
printf("invalid optlen\n");
return 1;
}
printf("I/F is on '%s'\n", optval);
#endif
close(sock);
return 0;
Idea based on another post
Create socket
Connect
Get interface address
Get interface id and name from interface address
$ gcc -std=gnu11 -Wall so_q_63899229.c
$ ./a.out 93.184.216.34 # example.org
interface index : 2
interface name : wlp2s0
interface address : 192.168.1.223
remote address : 93.184.216.34
so_q_63899229.c
#include <arpa/inet.h>
#include <assert.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <unistd.h>
int sockfd=-1;
void connect2(const char *const dst){
sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd>=3);
struct sockaddr_in sin={
.sin_family=AF_INET,
.sin_port=htons(80),
.sin_addr={}
};
assert(1==inet_pton(AF_INET,dst,&(sin.sin_addr)));
assert(0==connect(sockfd,(struct sockaddr*)(&sin),sizeof(struct sockaddr_in)));
}
void getsockname2(struct sockaddr_in *const sin){
socklen_t addrlen=sizeof(struct sockaddr_in);
assert(0==getsockname(sockfd,(struct sockaddr*)sin,&addrlen));
assert(addrlen==sizeof(struct sockaddr_in));
}
void disconnect(){
close(sockfd);
sockfd=-1;
}
void addr2iface_ifconf(const struct in_addr *const sin_addr,int *const index,char *const name){
struct ifconf ifc={
.ifc_len=0,
.ifc_req=NULL
};
int ioctlfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
assert(ioctlfd>=3);
assert(0==ioctl(ioctlfd,SIOCGIFCONF,&ifc));
const int sz=ifc.ifc_len;
assert(sz%sizeof(struct ifreq)==0);
const int n=sz/sizeof(struct ifreq);
char buf[sz];
bzero(buf,sz);
ifc.ifc_buf=buf;
assert(0==ioctl(ioctlfd,SIOCGIFCONF,&ifc));
assert(
ifc.ifc_len==sz &&
(char*)ifc.ifc_req==buf
);
for(int i=0;i<n;++i)if(0==memcmp(
&(((struct sockaddr_in*)(&(ifc.ifc_req[i].ifr_addr)))->sin_addr),
sin_addr,
sizeof(struct in_addr)
)){
*index=ifc.ifc_req[i].ifr_ifindex;
assert(name==strncpy(name,ifc.ifc_req[i].ifr_name,IFNAMSIZ));
return;
}
assert(0);
}
int main(int argc,const char *argv[]){
assert(argc==2);
assert(argv[1]&&strlen(argv[1]));
const char *const remoteaddr_s=argv[1];
// const char *const remoteaddr_s="93.184.216.34";
connect2(remoteaddr_s);
struct sockaddr_in ifaddr={};
getsockname2(&ifaddr);
disconnect();
int index=0;
char ifname[IFNAMSIZ]={};
addr2iface_ifconf(&(ifaddr.sin_addr),&index,ifname);
char ifaddr_s[INET_ADDRSTRLEN]={};
assert(ifaddr_s==inet_ntop(AF_INET,&(ifaddr.sin_addr),ifaddr_s,INET_ADDRSTRLEN));
printf("interface index : %d\n",index);
printf("interface name : %s\n",ifname);
printf("interface address : %s\n",ifaddr_s);
printf("remote address : %s\n",remoteaddr_s);
// printf("#%d %s %s -> %s\n",
// index,
// ifname,
// ifaddr_s,
// remoteaddr_s
// );
return 0;
}
Also there doesn't seem to be an identifier named IFNAMSZ. IFNAMSIZ defined in <net/if.h> should be the maxinum legth (including '\0') allowed for the name of any interface IMHO.
I am using the UDP auxiliary functions encapsulated below replacing the calls the functions of the sockets libraries to simulate and allow some testing on the UDP client and server. But I am not able to make the connection between them and pass the arguments correctly.
/********auxiliary functions for using UDP sockets*********/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <strings.h>
#include "tp_socket.h"
#define MTU 1024
int tp_mtu(void)
{
fprintf(stderr,"tp_mtu called\n");
return MTU;
}
int tp_sendto(int so, char* buff, int buff_len, so_addr* to_addr)
{
int count;
fprintf(stderr,"tp_sendto called (%d bytes)\n", buff_len);
count = sendto(so, (void*)buff, buff_len, 0,
(struct sockaddr*) to_addr, sizeof(struct sockaddr_in));
fprintf(stderr,"tp_sendto returning (sent %d bytes)\n", count);
return count;
}
int tp_recvfrom(int so, char* buff, int buff_len, so_addr* from_addr)
{
int count;
unsigned int sockaddr_len = sizeof(struct sockaddr_in);
fprintf(stderr,"tp_recvfrom called (%d bytes)\n",buff_len);
count = recvfrom(so,(void*)buff,(size_t)buff_len,0,
(struct sockaddr*) from_addr, &sockaddr_len);
fprintf(stderr,"tp_recvfrom returning (received %d bytes)\n",count);
return count;
}
int tp_init(void)
{
fprintf(stderr,"tp_init called\n");
return 0;
}
int tp_socket(unsigned short port)
{
int so;
struct sockaddr_in local_addr;
int addr_len =sizeof(local_addr);
fprintf(stderr,"tp_socket called\n");
if ((so=socket(PF_INET,SOCK_DGRAM,0))<0) {
return -1;
}
if (tp_build_addr(&local_addr,INADDR_ANY,port)<0) {
return -2;
}
if (bind(so, (struct sockaddr*)&local_addr, sizeof(local_addr))<0) {
return -3;
}
return so;
}
int tp_build_addr(so_addr* addr, char* hostname, int port)
{
struct hostent* he;
fprintf(stderr,"tp_build_addr called\n");
addr->sin_family = PF_INET;
addr->sin_port = htons(port);
if (hostname==NULL) {
addr->sin_addr.s_addr = INADDR_ANY;
} else {
if ((he=gethostbyname(hostname))==NULL) {
return -1;
}
bcopy(he->h_addr,&(addr->sin_addr.s_addr),sizeof(in_addr_t));
}
return 0;
}
My code at the moment of the UDP client:
/********clientUDP*********/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include "tp_socket.h"
int main(int argc, char *argv[])
{
so_addr to_addr;
char *ip_server;
char my_buffer[10];
int port_servidor, tam_buffer;
if (argc != 5)
{
perror("Error");
exit(-1);
}
*ip_server = argv[1];
port_server = atoi(argv[2]);
char arquivo = argv[3];
tam_buffer = atoi(argv[4]);
tp_init();
tp_socket(port);
tp_build_addr(&to_addr, ip_server, port_server);
exit(0);
}
My code at the moment of the UDP server:
/********serverUDP*********/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include "tp_socket.h"
int main(int argc, char *argv[])
{
so_addr my_addr;
int aux, so, mtu, port_server,tam_buffer,n;
char *archive;
char buffer[10];
FILE *file;
if (argc != 3)
{
perror("Error");
exit(-1);
}
port_server = atoi(argv[1]);
tam_buffer = atoi(argv[2]);
aux = tp_init();
if (aux < 0)
{
perror("error");
exit(aux);
}
mtu = tp_mtu();
so = tp_socket(port_server);
tp_recvfrom(so, buffer, 10 , &my_addr);
n = read( so,tam_buffer,1);
file = fopen(archive,"r");
if ( file != NULL )
{
n=fread(buffer,1,atoi(argv[2]),file);
while ( n > 0)
{
write(so,buffer,n);
n=fread(buffer,1, atoi(argv[2]),file);
}
} else
{
printf("error\n");
exit(0);
}
fclose(file);
shutdown(so,2);
close();
return 0;
}
Could someone please explain how I use the auxiliary functions to connect the client to the server and transfer files? I've be I've been locked up a long time at this stage.
I have a simple program in C, which resolves IP addresses into hostnames.
#include <stdio.h> /* stderr, stdout */
#include <netinet/in.h> /* in_addr structure */
#include <strings.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char **argv) {
if ( argc == 2) {
struct sockaddr_in sa;
sa.sin_family = AF_INET;
inet_pton(AF_INET, argv[1], &sa.sin_addr);
char node[NI_MAXHOST];
int res = getnameinfo((struct sockaddr*)&sa, sizeof(sa), node, sizeof(node), NULL, 0, 0);
if (res)
{
printf("%s\n", gai_strerror(res));
return 1;
}
printf("%s\n", node);
return 0;
}
}
It works fine (i.e. ./a.out 10.1.1.2) but I need to modify it so that it accepts IP addresses in HEX format.
Is there some function to convert hex IP addresses to decimal?
I haven't tested this but should work.
#include <stdio.h> /* stderr, stdout */
#include <netinet/in.h> /* in_addr structure */
#include <strings.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char **argv) {
if ( argc == 2) {
struct sockaddr_in sa;
char a[2048] = {'\0'}; // placeholder not to overflow and initialised.
if( NULL == strchr(argv[1],'.') )
{
unsigned int unit0, uint1, uint2, uint3;
sscanf(argv[1], "%2x%2x%2x%2x", &uint0, &uint1, &uint2, &uint3);
sprintf(a,"%u.%u.%u.%u",uint0, uint1, uint2, uint3);
}
else
strcpy(a.argv[1]);
sa.sin_family = AF_INET;
inet_pton(AF_INET, a, &sa.sin_addr);
char node[NI_MAXHOST];
int res = getnameinfo((struct sockaddr*)&sa, sizeof(sa), node, sizeof(node), NULL, 0, 0);
if (res)
{
printf("%s\n", gai_strerror(res));
return 1;
}
printf("%s\n", node);
return 0;
}
}
Thanks
I'm trying to write a simple code for a server to print something from a function
This code gives me an error :
request for member ‘sin_addr’ in something not a structure or union
and I don't understand why
can you help me?
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <unistd.h>
#include <stdio.h>
void printsin(struct sockaddr_in *s, char *str1, char *str2) {
printf("%s\n", str1);
printf("%s: ", str2);
printf("%d = ,", s.sin_addr.s_addr);
printf(" %d = ", s.sin_port);
printf("\n");
}
int main(int argc, char *argv[])
{
int socket_fd, cc, fsize;
struct sockaddr_in s_in, from;
struct { char head; u_long body; char tail;} msg;
socket_fd = socket (AF_INET, SOCK_DGRAM, 0);
bzero((char *) &s_in, sizeof(s_in)); /* They say you must do this */
s_in.sin_family = (short)AF_INET;
s_in.sin_addr.s_addr = htonl(INADDR_ANY); /* WILDCARD */
s_in.sin_port = htons((u_short)0x3333);
printsin( &s_in, "RECV_UDP", "Local socket is:");
fflush(stdout);
bind(socket_fd, (struct sockaddr *)&s_in, sizeof(s_in));
for(;;) {
fsize = sizeof(from);
cc = recvfrom(socket_fd,&msg,sizeof(msg),0,(struct sockaddr *)&from,&fsize);
//printsin( &from, "recv_udp: ", "Packet from:");
printf("Got data ::%c%ld%c\n",msg.head,(long) ntohl(msg.body),msg.tail);
fflush(stdout);
}
return 0;
}
Thank you
printf("%d = ,", s->sin_addr.s_addr);
printf(" %d = ", s->sin_port);
That should fix it you pass it in as a pointer then you never deference it.
I wanted to get the IP address and the subnet mask. Now the IP part is done, however I couldn't find any socket function that would return a structure with the subnet mask in it.
Does a socket function exist, that returns it in a structure?
Thanks!
In Unix using getifaddrs
struct ifaddrs haves a member named ifa_netmask (Netmask of interface)
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
int main ()
{
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
char *addr;
getifaddrs (&ifap);
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family==AF_INET) {
sa = (struct sockaddr_in *) ifa->ifa_netmask;
addr = inet_ntoa(sa->sin_addr);
printf("Interface: %s\tAddress: %s\n", ifa->ifa_name, addr);
}
}
freeifaddrs(ifap);
return 0;
}
Output
Interface: lo Address: 255.0.0.0
Interface: eth0 Address: 255.255.255.0
In windows using IPHelper.
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "IPHLPAPI.lib")
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
/* Note: could also use malloc() and free() */
int __cdecl main()
{
PIP_ADAPTER_INFO pAdapterInfo;
ULONG ulOutBufLen = sizeof (IP_ADAPTER_INFO);
pAdapterInfo = (IP_ADAPTER_INFO *) MALLOC(sizeof (IP_ADAPTER_INFO));
GetAdaptersInfo(pAdapterInfo, &ulOutBufLen);
printf("\tIP Mask: \t%s\n", pAdapterInfo->IpAddressList.IpMask.String);
}
if (pAdapterInfo)
FREE(pAdapterInfo);
return 0;
}
Borrowed code from Linux Man page and referred to the code from Keine Lust:
#define _GNU_SOURCE /* To get defns of NI_MAXSERV and NI_MAXHOST */
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_link.h>
#include <string.h> /* strcasecmp() */
int get_addr_and_netmask_using_ifaddrs(const char* ifa_name,
char *addr, char *netmask)
{
struct ifaddrs *ifap, *ifa;
struct sockaddr_in *sa;
char *s;
int found = 0;
if (getifaddrs(&ifap) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
for (ifa = ifap; ifa && !found; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL)
continue;
if (strcasecmp(ifa_name, ifa->ifa_name))
continue;
/* IPv4 */
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
sa = (struct sockaddr_in *) ifa->ifa_addr;
s = inet_ntoa(sa->sin_addr);
strcpy(addr, s);
sa = (struct sockaddr_in *) ifa->ifa_netmask;
s = inet_ntoa(sa->sin_addr);
strcpy(netmask, s);
found = 1;
}
freeifaddrs(ifap);
if (found)
return EXIT_SUCCESS;
return EXIT_FAILURE;
}
int main(void)
{
char *addr = malloc(NI_MAXHOST);
char *netmask = malloc(NI_MAXHOST);
if (!get_addr_and_netmask_using_ifaddrs ("enp6s0", addr, netmask))
printf("[%s]%s %s\n", __func__, addr, netmask);
else
printf("interface error.\n");
free(addr);
free(netmask);
return 0;
}