I know you can get the destination address for messages coming into a SOCK_DGRAM socket by using recvmsg. I would like to know how to get the destination address (from peer perspective) for a socket created by calling the accept function on a socket of type SOCK_STREAM. In other words, how can I get the destination address of the SYN packet that caused accept to return?
Perhaps with getpeername system call?
The function you look for is getpeername.
Related
I was trying to write some codes using raw sockets, while I observed some strange phenomenon. Consider the code:
int rsfd = socket(AF_INET,SOCK_RAW,253);
if(rsfd<0)
{
perror("Raw socket not created");
}
else
{
struct sockaddr_in addr2;
memset(&addr2,0,sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = inet_addr("127.0.0.2");
/* if(connect(rsfd,(struct sockaddr*)&addr2,sizeof(addr2))<0)
{
perror("Could not connect");continue;
} */
}
Now if I remove the commented portion, whatever message I am sending through this rsfd is also being received by itself. On the other end I have already bound a socket with the ip address 127.0.0.2. When I printed the ip address of the sender socket, it is printing 127.0.0.1 but still it is receiving packets which is meant for 127.0.0.2. This problem was solved when I added that connect request which is mentioned in the commented portion. This seems weird because on the other side, no one is accepting or listen on this address and moreover, I am using sendto and recvfrom functions for sending and receiving packets which is used for connection less sockets. My question is, why is this happening? How is this connect request solvong the problem here?
Now if I [don't connect() the socket], whatever message I am sending through this rsfd is also being received by itself.
I note first that raw sockets are an extension to POSIX. Linux offers them, and I think other systems do too, but details of their behavior are not certain to be consistent across implementations.
With that said, the problem seems likely to be that you are not bind()ing your socket to any address. On Linux, for example, the docs for raw sockets note that
A raw socket can be bound to a specific local address using the
bind(2) call. If it isn't bound, all packets with the specified IP
protocol are received.
(Emphasis added.) On a system where raw sockets have that behavior, if you're sending packets to an IP loopback address via a raw IP socket that is neither bound nor connected then yes, the source socket will receive them, or at least may do.
It's unclear why connecting the socket solves the problem, or why it is even successful at all. The behavior of connect() is unspecified for socket types other than the standard ones, SOCK_DGRAM, SOCK_STREAM, and SOCK_SEQPACKET. However, the behavior you observe is consistent with connect() having an effect on raw sockets like that it has on datagram sockets, which are also connectionless:
If the socket sockfd is of type SOCK_DGRAM, then addr is the address
to which datagrams are sent by default, and the only address from
which datagrams are received.
Instead of relying on that discovered behavior, however, I suggest following the documented (at least on Linux) procedure of binding the socket to an address (including a port), and communicating with it at that address.
I'm sending some ping packets via a raw socket in C, on my linux machine.
int sock_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
This means that I specify the IP packet header when I write to the socket (IP_HDRINCL is implied).
Writing to the socket with send fails, telling me I need to specify an address.
If I use sendto then it works. For sendto I must specify a sockaddr_in struct to use, which includes the fields sin_family, sin_port and sin_addr.
However, I have noticed a few things:
The sin_family is AF_INET - which was already specified when the socket was created.
The sin_port is naturally unused (ports are not a concept for IP).
It doesn't matter what address I use, so long as it is an external address (the IP packet specifies 8.8.8.8 and the sin_addr specifies 1.1.1.1).
It seems none of the extra fields in sendto are actually used to great extent. So, is there a technical reason why I have to use sendto instead of send or is it just an oversight in the API?
Writing to the socket with send fails, telling me I need to specify an address.
It fails, because the send() function can only be used on connected sockets (as stated here). Usually you would use send() for TCP communication (connection-oriented) and sendto() can be used to send UDP datagrams (connectionless).
Since you want to send "ping" packets, or more correctly ICMP datagrams, which are clearly connectionless, you have to use the sendto() function.
It seems none of the extra fields in sendto are actually used to great
extent. So, is there a technical reason why I have to use sendto
instead of send or is it just an oversight in the API?
Short answer:
When you are not allowed to use send(), then there is only one option left, called sendto().
Long answer:
It is not just an oversight in the API. If you want to send a UDP datagram by using an ordinary socket (e.g. SOCK_DGRAM), sendto() needs the information about the destination address and port, which you provided in the struct sockaddr_in, right? The kernel will insert that information into the resulting IP header, since the struct sockaddr_in is the only place where you specified who the receiver will be. Or in other words: in this case the kernel has to take the destination info from your struct as you don't provide an additional IP header.
Because sendto() is not only used for UDP but also raw sockets, it has to be a more or less "generic" function which can cover all the different use cases, even when some parameters like the port number are not relevant/used in the end.
For instance, by using IPPROTO_RAW (which automatically implies IP_HDRINCL), you show your intention that you want to create the IP header on your own. Thus the last two arguments of sendto() are actually redundant information, because they're already included in the data buffer you pass to sendto() as the second argument. Note that, even when you use IP_HDRINCL with your raw socket, the kernel will fill in the source address and checksum of your IP datagram if you set the corresponding fields to 0.
If you want to write your own ping program, you could also change the last argument in your socket() function from IPPROTO_RAW to IPPROTO_ICMP and let the kernel create the IP header for you, so you have one thing less to worry about. Now you can easily see how the two sendto()-parameters *dest_addr and addrlen become significant again because it's the only place where you provide a destination address.
The language and APIs are very old and have grown over time. Some APIs can look weird from todays perspective but you can't change the old interfaces without breaking a huge amount of existing code. Sometimes you just have to get used to things that were defined/designed many years or decades ago.
Hope that answers your question.
The send() call is used when the sockets are in a TCP SOCK_STREAM connected state.
From the man page:
the send() call may be used only when the socket is in a connected
state (so that the intended recipient is known).
Since your application obviously does not connect with any other socket, we cannot expect send() to work.
In addition to InvertedHeli's answer, the dest_addr passed in sendto() will be used by kernel to determine which network interface to used.
For example, if dest_addr has ip 127.0.0.1 and the raw packet has dest address 8.8.8.8, your packet will still be routed to the lo interface.
I am using a socket to receive alert information from snort packets.
I am using the readme-unsock file as a base. I cant extract the IP addresses from the packet. I get the wrong data structure from the packet. is there a way of changing this? (Apologies i'm new)
case IPPROTO_TCP:
inet_ntoa (p->iph->ip_dst);
Error message received
inet_ntoa() is deprected - https://beej.us/guide/bgnet/output/html/multipage/inet_ntoaman.html
use inet_ntop() instead - http://man7.org/linux/man-pages/man3/inet_ntop.3.html
The socket is created and bound, then the program receives data with recv(). The question is: How do I now determine from which host + port the packet originates so that I can send data back?
Note: C and Winsock is used.
Use recvfrom instead, it can return the source port and address
My initial UDP socket is binded to 127.0.0.1:9898.
The first time that I get notified of incoming data by epoll/kqueue, I do recvfrom() and I fill a struct sockaddr called peer_name that contain the peer informations (ip:port).
Then I create a new UPD socket using socket(),
then I bind() this newly created socket to the same ip:port (127.0.0.1:9898) than my original socket.
then I connect my newly created socket using connect() to the peer who just sent me something. I have the information in the struct sockaddr called peer_name.
I then add my newly created socket in my epoll/kqueue vector and wait for notification.
I would expect to ONLY receive UDP frame from the peer i'm ""connected to"".
1/ does netstat -a -p udp is suppose to show me the IP:PORT of the peer my newly created socket is ""connected to"" ?
2/ I'm probably doing something wrong since after creating my new socket, this socket receive all incoming UDP packets destinated to the IP:PORT I'm binded to, regardless of the source peer IP:PORT.
I would like to see a working example of what I'm trying to do :)
or any hint on what I'm doing wrong.
thanks!
http://www.softlab.ntua.gr/facilities/documentation/unix/unix-socket-faq/unix-socket-faq-5.html
"Does doing a connect() call affect the receive behaviourof the socket?
Yes, in two ways. First, only datagrams from your "connected peer" are returned. All others arriving at your port are not delivered to you.
But most importantly, a UDP socket must be connected to receive ICMP errors. Pp. 748-749 of "TCP/IP Illustrated, Volume 2" give all the gory details on why this is so."
connect(2) on a UDP socket just sets the default destination address of the socket (where the data will be sent if you use write(2) or send(2) on the socket). It has no other effect -- you can still send packets to other addresses with sendto(2) or sendmsg(2) and you'll still see packets sent from any address.
So it doesn't really make any sense to open a new socket on the port -- for every packet received, you need to look at the source address to see if it comes from an address you've seen already (and thus belongs to that logical stream) or is a new address (a new logical stream).