How to obtain socket domain of not connected, nor binded socket - c

The title says it all. On Linux, how to know a domain of a not connected, nor binded socket.
Here is the code for reference.
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(int argc, char *argv[])
{
int sd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
int domain;
socklen_t s_len;
if(sd < 0){
perror("socket DID NOT create");
return 1;
}
if(getsockopt(sd, SOL_SOCKET, SO_DOMAIN, &domain, &s_len) < 0){
perror("getsockopt failed");
return 2;
}
const char *so_domain = NULL;
if(domain == AF_UNIX)
so_domain = "AF_UNIX";
printf("sock domain is: %d : %s\n", domain, so_domain);
return 0;
}
The code returns zero for the domain.

You are passing an uninitialised value of s_len to getsockopt(). From the manpage:
For getsockopt(), optlen is a value-result argument, initially containing the size
of the buffer pointed to by optval, and modified on return to indicate
the actual size of the value returned.
Changing it to:
socklen_t s_len = sizeof domain;
fixes it. Output:
sock domain is: 1 : AF_UNIX

Related

Sending a UDP broadcast is detected by TCPdump as leaving OpenWRT router, but not by Wireshark on the receiving computer

My network consists of the GL-MT300N-V2 router running this code:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <time.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int sock;
if( (sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
perror("socket : ");
return -1;
}
int broadcast = 1;
if( setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) != 0 )
{
perror("setsockopt BROADCAST: ");
close(sock);
return -1;
}
char netif[] = "eth0";
if( setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, netif, sizeof(netif) )
{
perror("setsockopt BIND : ");
close(sock);
return -1;
};
char *ip = "255.255.255.255";
char * msg = "OOO"; //Actual code has 250 'O's to be visible in the dump
struct sockaddr_in si;
si.sin_family = AF_INET;
si.sin_port = htons( 4444 );
inet_aton( ip, &si.sin_addr.s_addr );
/* send data */
for(int i = 0; i < 10000; i ++) //Used to spam for tcpdump
{
size_t nBytes = sendto(sock, msg, strlen(msg), 0,
(struct sockaddr*) &si, sizeof(si));
if(i % 1000 == 0)
{
printf("Sent msg: %s, %d bytes with socket %d to %s\n", msg, nBytes, sock, ip);
}
}
return 0;
}
The code successfully continually and rapidly sends packets. Said packets are easily visible in TCPdump. However, when I connect the router to a Windows 10 PC or laptop using ethernet, the computers are unable to detect the packets with Wireshark.
The sheer amount of packets is likely not the problem, as other code I have run sends similar amounts of packets, all of which are received.
Windows firewall has also been disabled, so the packet isn't being dropped there either.
It could be an interface optimization--drop it in hardware, so to speak (assuming port 0x4444 is not LISTENING--check netstat). For obvious reasons, you do not want to send all bcasts up the stack.

How to find the network interface used by a connected socket

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.

global table of clients C : Chatroom

I created a client/server chatroom in C. I need to put in a global table of all clients connected so that I can send every message the server receives to all the clients connected. I can't figure out how to do this. I assume I have to create a struct of some sort and add every specific socket descriptor for each thread I spawn. Then I have to send my message to every specific SD in that struct.
I don't know how to code this and wanted to see if anyone could show me some example code of what I have to write after every connection is made and what I have to write to then send my messages to every thread. My server code is below if needed.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <errno.h>
#include <netdb.h>
#include <sys/stat.h>
#include <fcntl.h>
void *
client_session_thread(void * arg)
{
int SD;
char request[2048];
char message[2048] = "server receives input: ";
int chatfile;
char msgr[50000];
SD = *(int *)arg;
free (arg);
pthread_detach(pthread_self());
chatfile = open("chathistory.txt", O_RDWR|O_CREAT|O_EXCL,0666);
close(chatfile);
chatfile = open("chathistory.txt", O_RDWR | O_APPEND);
read(chatfile,msgr,sizeof(msgr));
write(SD, msgr, strlen(msgr));
while (read(SD, request, sizeof(request)))
{
strcat(message, request);
strcat(message,"\n");
fprintf(stdout, message);
write(SD,request,strlen(request));
write(chatfile,request,strlen(request));
strcpy(request,"");
strcpy(message, "server receives input: ");
bzero(request, sizeof(request));
bzero(message,sizeof(message));
}
close(SD);
close(chatfile);
return 0;
}
int main(int argc, char *argv[])
{
//create a socket. SD is my socket.
struct addrinfo addrinfo;
struct addrinfo * result;
char message[256];
int SD;
int FD;
pthread_t ignore;
int * FDpntr;
int on = 1;
addrinfo.ai_flags = 0;
addrinfo.ai_family = AF_INET; // IPv4 only
addrinfo.ai_socktype = SOCK_STREAM; // Want TCP/IP
addrinfo.ai_protocol = 0; // Any protocol
addrinfo.ai_addrlen = 0;
addrinfo.ai_addr = NULL;
addrinfo.ai_canonname = NULL;
addrinfo.ai_next = NULL;
if (getaddrinfo("clamshell.rutgers.edu", "5700", &addrinfo, &result) !=0)
{
printf("\x1b[1;31mProblem with getaddrinfo\x1b[0m\n");
}
//Create socket
SD = socket(AF_INET, SOCK_STREAM, 0);
if (SD == -1)
{
printf("\x1b[1;31mProblem creating socket\x1b[0m\n");
}
//Bind the socket to our specified IP and port
if (setsockopt(SD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) ==-1)
{
printf("\x1b[1;31mProblem with sockopt\x1b[0m\n");
freeaddrinfo(result);
return -1;
}
if (bind(SD, result->ai_addr, result->ai_addrlen) != 0)
{
printf("\x1b[1;31mProblem binding socket\x1b[0m\n");
}
//first we bind our socket and then recast our address just like in client
//Listen function listens for connections
if (listen(SD, 20) == -1)
{
printf("\x1b[1;31mProblem with listen\x1b[0m\n");
close(SD);
return 0;
}
else
{
//Accept function for accepting incoming connection
//sos = sizeof(struct sockaddr_in);
//while (FD = accept(SD, (struct sockaddr *)&client, (socklen_t*)&sos))
while ((FD = accept(SD,0,0)) != -1)
{
FDpntr = (int *)malloc(sizeof(int));
*FDpntr = FD;
if (pthread_create(&ignore, NULL, client_session_thread, FDpntr) != 0)
{
printf("\x1b[1;31mProblem creating thread\x1b[0m\n");
}
else
{
continue;
}
}
close(SD);
return 0;
}
}
suggest implement a separate file.
That file would have entry points:
initializeClientTable()
destroyClientTable()
addClient()
deleteClient(),
getClient()
The getClient() function would return a client.
it would have a parameter that (probably an enum value) that indicates to get the first client or get the next client from the ClientTable
When at the end of the ClientTable, return an indication of such event.
The ClientTable could easily be implemented as a linked list.

OS X getsockopt: no SO_PROTOCOL

OS X doesn't offer the SO_PROTOCOL socket option which allows the caller to "...retrieve the socket type as an integer." (http://linux.die.net/man/7/socket)
In other words the following program builds and works under linux but won't compile under OS X:
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
int main(int argc, char **argv)
{
int c, s, type, len;
len = sizeof(type);
s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s < 0)
{
fprintf(stderr, "socket kaboom: %s\n", strerror(errno));
return 1;
}
if (getsockopt(s, SOL_SOCKET, SO_PROTOCOL, &type, &len) < 0)
{
fprintf(stderr, "getsosockopt kaboom: %s\n", strerror(errno));
return 1;
}
printf("socket type: %d\n", type);
return 0;
}
How to accomplish this under OS X?
The standard SO_TYPE socket option, which returns values like SOCK_STREAM (corresponding to TCP) and SOCK_DGRAM (corresponding to UDP), should suffice. With SCTP, SOCK_STREAM might correspond to TCP or SCTP and SO_PROTOCOL is useful to distinguish them, but MacOS X does not support SCTP.
Unix domain sockets do not use protocol numbers; therefore, SO_TYPE is the right choice there as well.

Check port reachable in C

I have a C function to check a host and its port, when I use FQDN host name, the function return error like: connect() failed: connect time out, but if I use IP address instead, it seems ok, how to fix this?
Thanks.
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
int is_network_up(char *chkhost, unsigned short chkport) {
int sock;
struct sockaddr_in chksock;
struct hostent *host = NULL;
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
syslog(LOG_ERR, "socket() creation error: %s", strerror(errno));
return 0;
}
memset(&chksock, 0, sizeof(chksock));
chksock.sin_family = AF_INET;
chksock.sin_port = htons(chkport);
/* get the server address */
if (inet_pton(AF_INET, chkhost, &(chksock.sin_addr.s_addr)) <= 0) {
if ((host = gethostbyname(chkhost)) == NULL) {
syslog(LOG_ERR, "%s", hstrerror(h_errno));
return 0;
}
memcpy(&(chksock.sin_addr.s_addr), &(host->h_addr_list[0]),
sizeof(struct in_addr));
}
/* try to connect */
if (connect(sock, (struct sockaddr *) &chksock, sizeof(chksock)) < 0) {
syslog(LOG_ERR, "connect() failed: %s", strerror(errno));
return 0;
}
close(sock);
return 1;
}
inet_pton() is the wrong task for that. It only accepts numerical addresses.
In former times, people used to use gethostbyname() for name resolution.
But as we have 2012 meanwhile, this method is outdated for several years now, as it is still restricted to AF_INET.
With the program below, you should achieve about the same and stay future compatible.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <stdio.h>
int is_network_up(char *chkhost, unsigned short chkport) {
int sock = -1;
struct addrinfo * res, *rp;
int ret = 0;
char sport[10];
snprintf(sport, sizeof sport, "%d", chkport);
struct addrinfo hints = { .ai_socktype=SOCK_STREAM };
if (getaddrinfo(chkhost, sport, &hints, &res)) {
perror("gai");
return 0;
}
for (rp = res; rp && !ret; rp = rp->ai_next) {
sock = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sock == -1) continue;
if (connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) {
char node[200], service[100];
getnameinfo(res->ai_addr, res->ai_addrlen, node, sizeof node, service, sizeof
service, NI_NUMERICHOST);
printf("Success on %s, %s\n", node, service);
ret = 1; /* Success */
}
close(sock);
}
freeaddrinfo(res);
return ret;
}
int main(int argc, char** argv) {
if (argc > 1) {
printf("%s: %d\n", argv[1], is_network_up(argv[1], 22));
}
}
Make sure name resolution is working. See if you can ping the machine by name from the exact same environment in which your code runs.
If ping works, try telnet <machinename> <portnumber> -- If both of those work it is likely a problem with your code (which I did not look at in depth, too sleepy:).
Make sure you're converting anything returned by the OS as an ip address from network order to host order. IIRC, gethostbyname returns binary ip addresses in network order.
ntohl can be used on chksock.sin_addr.s_addr after the memcpy to achieve this.

Resources