why we still have the sun_family in the struct sockaddr_un? - c

I'm a newbie in UNIX programming. Normally, when we use local socket to communicate, the domain is always AF_UNIX or AF_LOCAL. So in this case, struct sockaddr_un serves always for the local communication. Why there is still "short sun_family"? For a historical reason?
struct sockaddr_un{
short sun_family; /*AF_UNIX*/
char sun_PATH[108]; /*path name */
};

You pass a sockaddr * to several socket functions (e.g. connect, bind, sendto) - these will look at the family variable before casting to e.g. sockaddr_un * or sockaddr_in *

Related

How to read sk_buff data if we have have sock structure of specific process?

I have written a program where I can access the sock struct of the specific process but want to read sport and dport by reading sk_buff. But, I am unable to access sk_buff from the sock struct. Is it possible to do it?
If buf is a struct sk_buff*, then its source and destination ports are
buf->sk->sk_num
buf->sk->sk_dport
respectively.
This works since struct sk_buff contains a pointer to a struct sock, which defines a few macros to allow easy access to the port numbers you're looking for.

Why after running a server socket and using shutdown() do I have a file in that directory?

So I am making a basic server and client program in C and after I run the program I end up with a really weirdly named file that I have to remove for the program to work again. I assume that I am closing the sockets incorrectly. Currently I am closing the sockets as follows:
shutdown(serverSocket, SHUT_RDWR);
shutdown(clientSocket, SHUT_RDWR);
Any idea on why this is occuring?
Edit: both of these functions are returning 0
Here is the code that is causing the issue:
char buf[1024];
struct sockaddr_in server, client;
int serverSocket = socket(PF_LOCAL, SOCK_STREAM, 0);
server.sin_family = AF_LOCAL;
server.sin_port = htons(54164);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
bind(serverSocket, (struct sockaddr *) &server, sizeof(server));
The file doesn't appear until I run the bind function.
It looks like you're using the wrong socket address structure. You are using struct sockaddr_in (which is for AF_INET family).
But when using the AF_LOCAL (a.k.a. AF_UNIX) family, bind is expecting you to pass a struct sockaddr_un, which specifies a path to your socket (in the file system).
According to the manpage for unix sockets:
A UNIX domain socket address is represented in the following structure:
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* pathname */
};
The sun_family field always contains AF_UNIX. On Linux sun_path is 108 bytes in size.
Additionally:
Binding to a socket with a filename creates a socket in the
filesystem that must be deleted by the caller when it is no longer
needed (using unlink(2)). The usual UNIX close-behind semantics
apply; the socket can be unlinked at any time and will be finally
removed from the filesystem when the last reference to it is closed.

sockaddr structure - (sys/socket.h)

Ive been reading the sys/socket.h all day and finally starting to understand it, and now starting to use it, however, I'm not sure why I can't assign a value to sa_family member of the sockaddr struct.
Specification sockaddr Structure:
struct sockaddr{
sa_family_t sa_family address family
char sa_data[] socket address (variable-length data)
};
Data Type: sa_family_t - Unsigned integral type (2-4 bytes)
Values:
Name Purpose Man page
AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX - Novell protocols
AF_NETLINK Kernel user interface device netlink(7)
AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)
AF_AX25 Amateur radio AX.25 protocol
AF_ATMPVC Access to raw ATM PVCs
AF_APPLETALK AppleTalk ddp(7)
AF_PACKET Low level packet interface packet(7)
AF_ALG Interface to kernel crypto API
Which is a bit confusing since these values are char data types not an unsigned int.
Simple Test:
#include<stdio.h>
#include<sys/socket.h>
int main(void){
struct sockaddr_in address;
address.sin_family = AF_INET;
printf("Socket Address Family: %s\n", address.sin_family);
return 0;
}
Error:
storage size of ‘address’ isn’t known
It should be printing out Socket Address Family: AF_INET... what am I missing here?
It is because you don't include the definition of that structure. The structure sockaddr_in is defined in <netinet/in.h>. For more details, see: sockaddr_in undeclared identifier

"UDP datagrams only" socket in C

In Linux, Ubuntu 14.04:
I'm writing a code that implements socket to send pure UDP datagrams which includes UDP header+payload, without any part of IP header.
I have created the socket
sokt_fd=socket(AF_INET, SOCK_RAW, IPPROTO_UDP)
Also, I have prepared the UDP header.
I want to leave the IP encapsulation process to the kernel.
I want to send the datagram over any available IP interface. (I do not want to specify the source IP, and also leave this task to the kernel).
Do I need to specify the destination IP address before sending the datagram.
I must use "sendto()" command to send the datagram; how I must fill the "sockaddr" data structure?
#include <netinet/in.h>
struct sockaddr
{
unsigned short sa_family;// address family, AF_xxx
char sa_data[14];// 14 bytes of protocol address
};
Don't use the sockaddr structure. Use sockaddr_in instead and cast it when you have to pass a sockaddr* to a function.
struct sockaddr_in myaddr;
int s;
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(3490);
inet_aton("63.161.169.137", &myaddr.sin_addr.s_addr);
s = socket(PF_INET, SOCK_STREAM, 0);
bind(s, (struct sockaddr*)myaddr, sizeof(myaddr));
The socket API is designed for different addressing families, others are Infrared and Bluetooth. Since AF_INET is only one of the families the API functions use the general sockaddr type in the parameters.
There is a nice explanation of this in Chapter 3, "Sockets Introduction" in the well-known book Unix Network Programming, The Sockets Networking API (Volume 1) by Richard Stevens et. al. Let me quote:
Most socket functions require a pointer to a socket address structure
as an argument. Each supported protocol suite defines its own socket
address structure. The names of these structures begin with
sockaddr_ and end with a unique suffix for each protocol suite.
For the IP (Internet protocol) suite, the structure is sockaddr_in so it follows that since your example is specifying the AF_INET address family when you created the socket that you would use the more specific sockaddr_in structure instead of the more generic sockaddr. The socket API, as a matter of efficiency uses the more generic sockaddr pointer in the signature prototype.
With regard to using send() versus sendto(), I have found that sendto() is used more commonly with UDP and send() with TCP sockets. Therefore, to answer your question in #3 above, with UDP you don't have to specify the destination address up front, but instead it is supplied as an argument to sendto().
For a given udp_datagram and datagram_length, your code might look something like this:
uint32_t address = inet_addr("1.2.3.4"); // can also provide hostname here
uint16_t port = 27890;
sockaddr_in_t dest_addr;
memset(*dest_addr, 0, sizeof(dest_addr));
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
dest_addr.sin_addr.s_addr = htonl(address);
sendto(socket_fd,
(const char*)upd_datagram,
datagram_length,
0,
reinterpret_cast<sockaddr_t*>(&dest_addr),
sizeof(dest_addr));
The address API really wanted to be object-oriented, but had to deal with the fact that C isn't an OO language. sockaddr can be seen as the "base class" and the parameter type that bind, connect, sendto, recvfrom, etc. use when they need an address. However, you must provide a "subclassed" address matching the socket domain that you're using. This is because Berkeley sockets can be used for a wide and extensible range of protocols. IPv4 and IPv6 are the most typical, but UNIX-based installs also support sockets as filesystem objects ("addressed" by path), and, for instance, a hypervisor driver can install support for special inter-VM or guest-to-host sockets. See man 7 socket for an overview.
If you use IPv4, you need to use sockaddr_in. If you use IPv6, you need to use sockaddr_in6. In both cases, you need to cast your pointer to a sockaddr*.
To fill in a sockaddr_in, you need to do something like this:
struct sockaddr_in inet_addr;
inet_addr.sin_family = AF_INET;
inet_addr.sin_port = htons(port);
inet_addr.sin_addr.s_addr = htonl(ip_address_as_number);
struct sockaddr* addr = (struct sockaddr*)&inet_addr;
htons and htonl stand for "host to network (short)" and "host to network (long)", respectively. You need this because there was a time at which network drivers were too dumb to abstract away the machine's endianness and we can't go back in time to fix them. (The network byte order is big endian.)

In socket prgramming in "C" how do I find out the IP address of the Client who is connecting to the Server?

In socket prgramming in "C" how do I find out the IP address of the Client who is connecting to the Server? How can the server get the client's IP address?
You didn't mention any API, but the accept function/system call generally accepts a sockaddr * argument where it stores the address of the peer.
int accept(int socket, struct sockaddr *restrict address, /* <---- */
socklen_t *restrict address_len);
Alternatively you can use getpeername to retrieve the same address at a later time.
int getpeername(int socket, struct sockaddr *restrict address,
socklen_t *restrict address_len);
If you happen to use winapi: accept, getpeername.

Resources