Why is port a string and not an integer? - http

The Port method returns a string and not an integer. What is the reason for that and is it safe to prefix the port with ":"?

This is because what appears after the colon can be either a port number or service name.
The following is a valid example where the service name is used instead of a port number:
listener, err := net.Listen("tcp", "localhost:https") // port 443
// ...
The port mapping for a particular service can be looked up using net.LookupPort. On Unix systems, the /etc/services file is sourced for the mappings.

For a number the default value is 0: if a function
func (u * URL) Port () string
return number instead of sting the port will be 0
Port 0 is a reserved port in TCP/IP networking, meaning that it should not be used in TCP or UDP messages. However, port 0 carries special significance in network programming, particularly Unix socket programming: for requesting system-allocated, dynamic ports.
it is a need for programming in several functions

Related

What defines the max integer value for a URI port?

RFC 3986 defines the port of a URI as below -- zero or more digits. http/https URLs are defined to dereference over TCP, so ports would be limited to [1,65535], but in the general case of URIs of various schemes I'm having trouble finding a clear maximum.
For context, I'm writing a library that parses and handles URIs, and I want to make sure the library is sufficiently general.
3.2.3. Port
The port subcomponent of authority is designated by an optional
port number in decimal following the host and delimited from it by
a single colon (":") character.
port = *DIGIT
A scheme may define a default port. For example, the "http" scheme
defines a default port of "80", corresponding to its reserved TCP
port number. The type of port designated by the port number (e.g.,
TCP, UDP, SCTP) is defined by the URI scheme. URI producers and
normalizers should omit the port component and its ":" delimiter if
port is empty or if its value would be the same as that of the
scheme's default.
For TCP, UDP and SCTP port range is the same as your original message - [1, 65535]. That can be validated with appropriate RFCs (TCP, UDP, SCTP).
If you want to support any other transport protocols you need to look into their specification to see the range. However quite likely it will be the same.

Ada GNAT.Sockets send on multiple ethernet adaptors?

I have a machine with 4 Ethernet Interfaces (ensf1s1, ensf1s2, ensf1s3, ensf1f4) and using GNAT.Sockets I need to be able to send/recieve data over each interface.
The code I am using is
Create_Socket(SendFrom1, Family_Inet, Socket_Datagram);
Create_Socket(SendFrom2, Family_Inet, Socket_Datagram);
...
Bind_Socket(SendFrom1, SendFrom1Address);
Bind_Socket(SendFrom2, SendFrom2Address);
...
Channel1 := Stream(SendFrom1, SendToAddress1);
Channel2 := Stream(SendFrom2, SendToAddress2);
...
With IP addresses configured as 192.168.1.(101/102/103/104) I am getting all messages sent over a single interface with the correctly specified Source and Destination IPs in the packet.
I read in another question that having multiple NICs on the same subnet could cause a problem to some OS's so I changed to 192.168.1.101, 192.168.2.102 etc with a Subnet mask of 255.255.0.0. Using the same code with Addresses corrected this only sent data intended for the interface which previously sent all messages but nothing on the other 3.
Have I missed something in my Socket configuration to ensure a Socket is binded to the adaptor with the SendFromAddress specified? The OS is RHEL 7 if that's relevant.
Your question is related to how sockets are working.
If you bind your socket to a specific address, you will receive packets only for that destination address.
To receive packets from any of your four interfaces, you may bind to the INADDR_ANY address. You will do this as follows:
Address : GNAT.Sockets.Sock_Addr_Type;
SendFromAll : GNAT.Sockets.Socket_Type;
...
Address.Port := 0; -- Or whatever fixed port you like
Address.Addr := GNAT.Sockets.Any_Inet_Addr;
GNAT.Sockets.Bind_Socket (SendFromAll, Address);
Using this implementation, the SendFromAll socket will receive data from any interface. With Receive_Socket, you can get the sender address. Then when you send data back to the client using the SendFromAll socket, the system will pick an interface depending on the destination address and the network routing tables. On Linux, it will depend on the routing policy (ip rule) and on the routing tables (ip route).
Client : GNAT.Sockets.Sock_Addr_Type;
Buffer : Ada.Streams.Stream_Element_Array (0 .. 8192);
Last : Ada.Streams.Stream_Element_Offset;
....
GNAT.Sockets.Receive_Socket (SendFromAll, Buffer, Last, Client);
GNAT.Sockets.Send_Socket (SendFromAll, Buffer (Buffer'First .. Last), Last, Client);
Now if you really need to bind a socket to an interface, you must get the IP address of that interface. If you have several interfaces, you have to get their own IP addresses. There is no easy way with GNAT.Sockets to do this. You can use the Get_Host_By_Name function but you must setup different names for each interface (otherwise you'll get the same IP for each socket).
Another way which is not possible with GNAT.Sockets is to use the SO_BINDTODEVICE socket option. You bind the socket to the interface name (you don't need to get the IP).
What may happen to you is that you are using the same IP address for each Bind_Socket call.

Recover port from Boost Asio udp::endpoint

I am programming a server and client program to communicate between a windows PC using the Boost libraries and a Linux ARM beagleboard using the asio stand alone libraries. I have for a while had successful UDP communication between the two devices but now I want to recover the port from the endpoint the server discovers when the client connects. The way the client connects is via query:
udp::resolver resolver(io_service);
udp::resolver::query query_tx(udp::v4(), hostIP, "43210");
udp::endpoint receiver_endpoint_tx = *resolver.resolve(query_tx);
where host IP is a string and this works fine. Upon debugging though I notice that when i check the value returned by:
receiver_endpoint_tx.port()
This returns 51880. Now don't jump the guns and yell out network byte order and host byte order. I AM AWARE. The strange part is that this number 51880 sometimes is a different number and when i check what the server has stored in its endpoint it is a completely different number: 21743. Now I know I must be doing something wrong with the byte orders but i tried:
//unsigned long port_long = boost::asio::detail::socket_ops::host_to_network_long(receiver_endpoint_tx.port());
//unsigned long port_short = boost::asio::detail::socket_ops::host_to_network_short(receiver_endpoint_tx.port());
And they do not give me back my original port: 43210. Neither does network to host. So what am i missing and how can I on both ends recover my 43210 port? Obviously it must be there somewhere because they are successfully communicating.
Thanks in advance, sorry if noob mistake :)
Fistly, UDP is connectionless, there is no connection.
I'm not sure if I understand you correctly, but it sound too me like you want to bind to specific port numbers. If you want the client to send a packet from port x to port y on the server, and the server should respond from port y to port x, then you need to bind the sockets to the desired ports. Alternatively you can use the constructor to bind. Not doing so will result in the OS using ephemeral ports.
Further, to get the remote endpoint that a packet was received from the async_receive_from takes the sender_endpoint reference parameter. When the read handler is called, you can retrieve host and port from it.

How does a system's TCP/IP stack differentiate between multiple programs connecting to the same address and port?

Suppose two web browsers are running on the same computer and are accessing the same website (in other words, accessing the same IP address on the same port).
How does the operating system recognize which packets are from/for which program?
Does each program have a unique id field in the TCP header? If so, what is the field called?
The two programs are not actually accessing the "same port." For purposes of TCP, a connection is defined by the tuple (src_ip,src_port,dst_ip,dst_port).
The source port is usually ephemeral, which means it is randomly assigned by the OS. In other words:
Program A will have:
(my_ip, 10000, your_ip, 80)
Program B will have:
(my_ip, 10001, your_ip, 80)
Thus, the OS can see those are different "connections" and can push the packets to the correct socket objects.
the source port number will be different even if the destination port number is the same. the kernel will associate the source port number with the process.
When the client opens a connection to destination port 80, it uses an arbitrary unused source port on the local machine, say 17824. The web server then responds to that client by sending packets to destination port 17824.
A second client will use a second unused port number, say 17825, and so the two sockets' packets will not be mixed up since they'll use different port numbers on the client machine.
Christopher's answer is partially correct.
Programs A and B actually have a handle to a socket descriptor stored in the underlying OS's socket implementation. Packets are delivered to this underlying socket, and then any process which has a handle to that socket resource can read or write it.
For example, say you are writing a simple server on a Unix like OS such as Linux or Mac OSX.
Your server accepts a connection, at which point a connection consisting of
( src IP, src Port, dest IP, dest Port )
comes in to existence in the underlying OS socket layer. You then fork a process to handle the connection - at this point you now have two processes with handles to the socket both of which can read / write it.
Typically ( always ) the original server will close it's handle to the socket and let the forked process handle it. There are many reasons for this, but the one that is not always obvious to people is that when the child process finishes it's work and closes the socket the socket will stay open and connected if the parent process still has an open handle to it.
By port number.
IP address is used to identify computer, and port is used to identify process(application) within the computer. When a port is used by one process, other processes can't use it any more. So if any packet is sent to that port, only the owner of that port can handle that packet.
Connections are identified by a pair of endpoints.
– Endpoint means (ip, port)
Os assigns random number as src port number so, when packet travels to the receiving side, it is treated as different process's msg, since src port numbers are different.

How to tell which interface the socket received the message from?

If a socket is bound to IN6ADDR_ANY or INADDR_ANY and you use a call such as recvfrom() to receive messages on the socket. Is there a way to find out which interface the message came from?
In the case of IPv6 link-scope messages, I was hoping that the from argument of recvfrom() would have the scope_id field initialized to the interface Id. Unfortunately it is set to 0 in my test program.
Anybody know of a way to find out this information?
dwc is right, IPV6_PKTINFO will work for IPv6 on Linux.
Moreover, IP_PKTINFO will work for IPv4 — you can see details in manpage ip(7)
I've constructed an example that extracts the source, destination and interface addresses. For brevity, no error checking is provided. See this duplicate: Get destination address of a received UDP packet.
// sock is bound AF_INET socket, usually SOCK_DGRAM
// include struct in_pktinfo in the message "ancilliary" control data
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &opt, sizeof(opt));
// the control data is dumped here
char cmbuf[0x100];
// the remote/source sockaddr is put here
struct sockaddr_in peeraddr;
// if you want access to the data you need to init the msg_iovec fields
struct msghdr mh = {
.msg_name = &peeraddr,
.msg_namelen = sizeof(peeraddr),
.msg_control = cmbuf,
.msg_controllen = sizeof(cmbuf),
};
recvmsg(sock, &mh, 0);
for ( // iterate through all the control headers
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
cmsg != NULL;
cmsg = CMSG_NXTHDR(&mh, cmsg))
{
// ignore the control headers that don't match what we want
if (cmsg->cmsg_level != IPPROTO_IP ||
cmsg->cmsg_type != IP_PKTINFO)
{
continue;
}
struct in_pktinfo *pi = CMSG_DATA(cmsg);
// at this point, peeraddr is the source sockaddr
// pi->ipi_spec_dst is the destination in_addr
// pi->ipi_addr is the receiving interface in_addr
}
Apart from binding to each interface, I'm not aware of a way with IPv4, per se.
IPv6 has added the IPV6_PKTINFO socket option to address this shortcoming. With that option in effect, a struct in6_pktinfo will be returned as ancillary data.
Its been a while since I've been doing C/C++ TCP/IP coding but as far as I remember on every message (or derived socket) you can get into the IP headers information. These headers should include the receiving address which will be the IP of the interface you are asking about.
Outside of opening a separate socket on each interface as Glomek suggested, the only way I know to do this definitively on Windows is to use a raw socket, e.g.,
SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
Each receive from this socket will be an IP packet, which contains both the source and destination addresses. The program I work on requires me to put the socket in promiscuous mode using the SIO_RCVALL option. Doing this means I get every IP packet the interface "sees" on the network. To extract packets expressly for my application requires me to filter the data using the addresses and ports in the IP and TCP/UDP headers. Obviously, that's probably more overhead than you're interested in. I only mention it to say this - I've never used a raw socket without putting it in promiscuous mode. So I'm not sure if you can bind it to INADDR_ANY and just use it as a regular socket from that point forward or not. It would seem to me that you can; I've just never tried it.
EDIT: Read this article for limitations regarding raw sockets on Windows. This biggest hurdle I faced on my project was that one has to be a member of the Administrators group to open a raw socket on Windows 2000 and later.

Resources