TCP Connections in Go - tcp

Here is my code:
package main
import (
"fmt"
"net"
)
func main() {
addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:8081")
listener, _ := net.ListenTCP("tcp", addr)
fmt.Printf("listener addr: %s\n", listener.Addr().String())
for {
conn, err := listener.AcceptTCP()
if err != nil {
// handle error
fmt.Println("err")
return
}
go handleConnection(conn)
}
}
func handleConnection(conn *net.TCPConn) {
fmt.Printf("conn addr: %s\n", conn.LocalAddr().String())
fmt.Printf("conn remote addr: %s\n", conn.RemoteAddr().String())
}
Output
listener addr: 127.0.0.1:8081
conn addr: 127.0.0.1:8081
conn remote addr: 127.0.0.1:1234
Why do listener and conn have the same address? In TCP, I thought a new socket was created for new connections.

It got me puzzled for a second, but this is correct. A new socket is indeed created (with a unique local+remote address tuple). This quote from wikipedia describes it pretty well:
A server may create several concurrently established TCP sockets with the same local port number and local IP address, each mapped to its own server-child process, serving its own client process. They are treated as different sockets by the operating system, since the remote socket address (the client IP address and/or port number) are different; i.e. since they have different socket pair tuples.
If you think about it other way around, i.e. outgoing connection, you don't find it strange seeing remote address being the same across many sockets (e.g. google.com:80), so the same holds for incoming connections.
Probably a nice side effect of this is that tools like netstat, when inspecting sockets, are nicely showing the source port, instead of random pairs.

No, your Listener is accepting connections in port 8081, so the LocalAddr is going to have that port. If you dial out to another server, you usually use a different port each time, though that's not required either.

Related

LwIP echo client with multiple netif interfaces, how to select a particular netif interface

On an STM32H753 I run an example tcp echo client from STM32Cube_FW_H7.
The board however has three network interfaces with different IP addresses, all serviced by LwIP (1x LAN8742 + 2x KSZ8851).
Using ping I verified the correct ports are responding, by disconnecting others.
For example IP 192.168.0.101 is assigned to port 1, IP 192.168.0.102 is assigned to port 2, and IP 192.168.0.103 is assigned to port 3.
In ethernetif*.c, the three interfaces got names "st", "M1", and "M2".
All works fine, but the tcp_echoclient_connect function always selects the 3rd port as the local port. How can I tell LwIP to select for example the 1st or 2nd port?
The tcp_echoclient_connect function calls
/* connect to destination address/port */
tcp_connect(echoclient_pcb, &DestIPaddr, DEST_PORT, tcp_echoclient_connected);
It then selects the 3rd interface (and IP address).
In tcp.c, the function tcp_connect shows how to obtain a suitable interface:
/* check if we have a route to the remote host */
if (ip_addr_isany(&pcb->local_ip)) {
/* no local IP address set, yet. */
struct netif *netif;
const ip_addr_t *local_ip;
ip_route_get_local_ip(&pcb->local_ip, &pcb->remote_ip, netif, local_ip);
if ((netif == NULL) || (local_ip == NULL)) {
/* Don't even try to send a SYN packet if we have no route
since that will fail. */
return ERR_RTE;
}
/* Use the address as local address of the pcb. */
ip_addr_copy(pcb->local_ip, *local_ip);
}
So I'd like to specify a particular netif (interface).
How can I do that?
When I run the tcp echo server, it uses the right interface.
I can send a message to the corresponding port and it responds back. The wrong port does not respond.
My source
https://github.com/bkht/LAN8742A_KSZ8851SNL_LwIP
Note:
ip_route_get_local_ip calls ip_route, which returns the first netif that matches the netmask. It's the function ip4_route in ip4.c.
For now, as I could not find another way to select a partiular netif, I created a few functions to select the desired netif by name:
In ip4.c
struct netif *ip4_route_by_name(const char *name, const ip4_addr_t *dest)
In tcp.c
err_t tcp_connect_by_name(const char *name, struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, tcp_connected_fn connected)
In the tcp_echoclient server, I specify a netif name when creating a connection:
/* from a specified netif connect to destination address/port */
tcp_connect_by_name("m1", echoclient_pcb, &DestIPaddr, DEST_PORT, tcp_echoclient_connected);
But maybe the functionality existed already to specify a netif which matches the netif name, MAC address, or IP address?

Why is port a string and not an integer?

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

TCP server created in C language not working on internet

I have created a very simple server program to accept a connection send "Hello World" back to client.I connected to server (localhost) using telnet and it works fine.Now I want to run it over internet and its not working. I tried binding it to my public IP address(search it on google) and it doesn't work.`server_socket=socket(AF_INET,SOCK_STREAM ,0);
serverAddr.sin_family = AF_INET;
serverAddr.sin_port= htons(7892);
serverAddr.sin_addr.s_addr = inet_addr("192.168.43.241");//htonl(INADDR_ANY);//INADDR_ANY;//inet_addr("157.48.97.106");
memset(serverAddr.sin_zero,'\0',sizeof serverAddr.sin_zero);
bind(server_socket, (struct sockaddr *)&serverAddr,sizeof(serverAddr) );
if(listen(server_socket,5)==0)
printf("listening\n");
addr_size=sizeof client_addr;
printf("IP address is: %s\n", inet_ntoa(serverAddr.sin_addr));
while(1)
{
client_socket= accept( server_socket,(struct sockaddr *)&client_addr,&addr_size);
printf("Waiting\n");
printf("client_socket %d\n",client_socket);
int pid=fork();
if(pid>0)
{
printf("PID:%d\n",pid);
dup2(0,client_socket);
}
else
{
dup2(client_socket,0);
printf("%d %d\n",pid,client_socket);
send(client_socket,buffer,strlen(buffer),0);
printf("Message Sent\n");
shutdown(client_socket,0);
close(client_socket);
perror("CLOSE");
printf("Connection Closed\n");
exit(0);
}
}`
In principal you can bind to 0.0.0.0 (which should be the same as the INADDR_ANY that you have in the comment) to listen on all IPv4 addresses. This means you will be able to accept loopback connections as well as connections on all network cards (and thereby from the outside). This should work for you (assuming the remaining program works reliably on loopback).
If you can't connect from outside of the PC on the same network you most likely have a firewall configuration issue. Some OSes by default block incoming connections from the outside if there's no explicit firewall rule that allows it.
If you want to connect from the internet to the PC and you are connected through a router with NAT you also have to configure the router to forward the connection correctly.

How does port numbering works for receiving MODBUS TCP packets?

I am running an application on my microcontroller(MSP432), which writes data to an Ethernet cable to send it over to PC.
I am using Packet sender to view the data received on the port(502) on PC from MC.
Data received on PC
As we can see in the above picture, the port numbers of MC are increment for every packet sent.
What will happen when it reaches to the maximum number?
Will it restart at some other port number and proceed with the process or will it stop?
Edit1: Modbus protocol library used from http://myarduinoprojects.com/modbus.html
Edit2:
Making a call to this function everytime i have a new data to send through MODBUS. Mb.Req(MB_FC_WRITE_MULTIPLE_REGISTERS, 0,11,0);
if (MbmClient.connect(ServerIp,502)) {
digitalWrite(GREEN_LED, HIGH);
#if DEBUG
//Serial.println("connected with modbus slave");
// Serial.print("Master : ");
for(int i=0;i<MbmByteArray[5]+6;i++) {
if(MbmByteArray[i] < 16){
//Serial.print("0");
}
//Serial.print(MbmByteArray[i],HEX);
if (i != MbmByteArray[5]+5) {
//Serial.print(".");
} else {
//Serial.println();
}
}
#endif
MbmClient.write(MbmByteArray,13+(Count*2));
MbmCounter = 0;
MbmByteArray[7] = 0;
MbmPos = Pos;
MbmBitCount = Count;
*state= true;
MbmClient.stop();
delay(100);
digitalWrite(GREEN_LED, LOW);
} else {
*state= false;
MbmClient.stop();
}
It seems you are using this Modbus example
I have never worked with that but I suppose that because the destination port in the code is the same you have in your sniffing image: 502
Probably you are repeatedly calling this method:
void MgsModbus::Req(MB_FC FC, word Ref, word Count, word Pos)
Inside this method you can see this line:
if (MbmClient.connect(ServerIp,502)) {
...
So every time you call that function a new connection is open. When you open a connection through a socket, the operating system or the network stack needs to select a source port and IP address from where the TCP message is sent.
This is why you see always a new source port and that port is increasing. This is what is called an ephemeral port. How the source port is selected by the TCP stack you are using is implementation dependent, though it's very common to begin with some port and every time a connection is open, it selects the next available port.
If the stack is well programmed, most probably your TCP stack will wrap around and begin with some specific port from 1024 up (First 1024 ports are restricted). The code I saw seems to close the port with this function:
MbmClient.stop()
You need to check ports, after being used, are closed. Otherwise, at some point you will run out of available ports (resource leak).
If you want your socket bound to a specific source port, you need to use a function similar to Linux socket bind
Now, a wiser way is to use all the time the same connection. You may need to modify that example.

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.

Resources