Showing posts with label TCP/IP. Show all posts
Showing posts with label TCP/IP. Show all posts

Thursday, 12 December 2019

How to open ports on Ubuntu

I've recently had a situation where I was running HTTP server (written in Go) on port 8080 on my Ubuntu machine and had to access it from my Windows machine (which was on the same network). At first I got a connection time out error and I assumed Ubuntu was just rejecting connections for not having 8080 port opened. I was right. I used UFW (Uncomplicated Firewall) to open port on my Linux machine. UFW comes with Ubuntu (18.04 in my case) so didn't have to install any additional packages.


Let's see all ufw commands:

$ ufw --help
Usage: ufw COMMAND

Commands:
 enable                          enables the firewall
 disable                         disables the firewall
 default ARG                     set default policy
 logging LEVEL                   set logging to LEVEL
 allow ARGS                      add allow rule
 deny ARGS                       add deny rule
 reject ARGS                     add reject rule
 limit ARGS                      add limit rule
 delete RULE|NUM                 delete RULE
 insert NUM RULE                 insert RULE at NUM
 route RULE                      add route RULE
 route delete RULE|NUM           delete route RULE
 route insert NUM RULE           insert route RULE at NUM
 reload                          reload firewall
 reset                           reset firewall
 status                          show firewall status
 status numbered                 show firewall status as numbered list of RULES
 status verbose                  show verbose firewall status
 show ARG                        show firewall report
 version                         display version information

Application profile commands:
 app list                        list application profiles
 app info PROFILE                show information on PROFILE
 app update PROFILE              update PROFILE
 app default ARG                 set default application policy

You need to be root in order to perform majority of ufw operations.

To check firewall's status (whether it's active or not):

$ sudo ufw status

To enable it:

$ sudo ufw enable

To open 8080 port for TCP connections:

$ sudo ufw allow 8080/tcp

To verify the result:

$ sudo ufw status

Status: active

To                         Action      From
--                         ------      ----
8080/tcp                   ALLOW       Anywhere                  
8080/tcp (v6)              ALLOW       Anywhere (v6) 

Resources:

UFW - Community Help Wiki

Tuesday, 15 May 2012

Listening TCP Socket

TCP is a connection-oriented transport protocol which means that end points have to establish a connection prior to sending any (payload) data. Server opens one socket only for listening for incoming connection requests that come from clients. When placing a socket into a listening state, a maximum number of pending incoming connections is set. Those connections are waiting to be accepted and when backlog gets full no new connections are accepted.

Operations on listening socket are:
Listening socket never gets into connected state and shutdown() called on it yields socket error 10057 - WSAENOTCONN (Socket is not connected).

Here is the timeline of one simple dialogue between the client and the server:

Client Server
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) sockListen= socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
- sockaddr_in sSockAddr;
sSockAddr.sin_family = AF_INET;
sSockAddr.sin_addr.s_addr = inet_addr("192.168.0.24");
sSockAddr.sin_port = htons(43501);

bind(sockListen, (SOCKADDR*)&sSockAddr, sizeof(sSockAddr));
- listen(sockListen, MAXPENDING)
struct sockaddr_in sockAddrRemoteNode;
memset(&sockAddrRemoteNode, 0, sizeof(sockAddrRemoteNode));
sockAddrRemoteNode.sin_family = AF_INET;
sockAddrRemoteNode.sin_addr.s_addr = inet_addr("192.168.0.24");
sockAddrRemoteNode.sin_port = htons(43501);

connect(sock, (struct sockaddr*) &sockAddrRemoteNode, sizeof(sockAddrRemoteNode));
struct sockaddr sockAddrClt;
int nSockAddrLen = sizeof(sockAddrClt);

sockClient = accept(sockListen, (struct sockaddr*) &sockAddrClt, &nSockAddrLen);
send(sock, buffSend, SEND_BUFF_SIZE, 0) int recvPacketLen = recv(sockClient, buffRecv, RECV_BUFF_SIZE, 0)
shutdown(sock, SD_BOTH) shutdown(sockClient, SD_BOTH)
closesocket(sock) closesocket(sockClient)
- closesocket(sockListen)

Friday, 4 November 2011

How to get notified when network adapters' IP addresses change? (Windows OS)

TCP/IP networking software requires at least one network adapter bounded to TCP/IP protocol stack. Each physical network card has unique MAC address and static or dynamic IP address. Static address (one or possibly more) is configured manually and dynamic address is assigned by Dynamic Host Configuration Protocol (DHCP) server (if DHCP is enabled; Obtain IP address automatically is ticked in TCP/IPv4 Properties window). Operating system maintains table which maps IP addresses to network interfaces. Use ipconfig command in command prompt window to display that table. If your adapter has DHCP enabled and you unplug/plug network cable (if using LAN adapter), disable/enable network adapter through adapter settings, issue ipconfig /release or /renew command, get out of/into WiFi range (if using WiFi adapter)...your adapter will loose existing or get a new IP address. NIC to IP address table will change.

Networking applications often need to be aware when changes in this table occur. Windows API function NotifyAddrChange notifies caller on this event. Here is an example of how to call it synchronously (when it's blocking):

#if !defined(_MT)
#error _beginthreadex requires a multithreaded C run-time library.
#endif

#include <winsock2.h>
#include <iphlpapi.h>
#include <Windows.h>
#include <iostream>
#include <sstream>
#include <process.h>
#include <iomanip>

#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

#define APP_RETURN_CODE_SUCCESS 0
#define APP_RETURN_CODE_ERROR 1

#define THREAD_RETURN_CODE_SUCCESS 0
#define THREAD_RETURN_CODE_ERROR 1

// 127.0.0.1 in network byte order
#define IP_LOCALHOST 0x0100007F

void PrintIPTable()
    PMIB_IPADDRTABLE pIPAddrTable;

 pIPAddrTable = (MIB_IPADDRTABLE*)malloc(sizeof(MIB_IPADDRTABLE));

 if(!pIPAddrTable) 
 {
  std::cout << "malloc() failed" << std::endl;
  return;
 }
  
 // Before calling AddIPAddress we use GetIpAddrTable to get
 // an adapter to which we can add the IP
 // Make an initial call to GetIpAddrTable to get the
 // necessary size into the dwSize variable
 
 DWORD dwSize = 0;

 if(GetIpAddrTable(pIPAddrTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER) 
 {
  free(pIPAddrTable);
  pIPAddrTable = (MIB_IPADDRTABLE*)malloc(dwSize);

  if(!pIPAddrTable) 
  {
   std::cout << "malloc() failed" << std::endl;
   return;
  }
 }
 
 DWORD dwRetVal = 0;
 LPVOID lpMsgBuf;

 // Make a second call to GetIpAddrTable to get the actual data we want
 if((dwRetVal = GetIpAddrTable(pIPAddrTable, &dwSize, 0)) != NO_ERROR ) 
 { 
  std::cout << "GetIpAddrTable() failed. Error code: " << dwRetVal << std::endl;
  
  if(FormatMessage(
   FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 
   NULL, dwRetVal, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),       
   (LPTSTR) & lpMsgBuf, 0, NULL)) 
  {
   std::cout << "\tError: " << lpMsgBuf << std::endl;
   LocalFree(lpMsgBuf);
  }

  free(pIPAddrTable);
  return;  
 }

 std::cout << "\tNum Entries: " << pIPAddrTable->dwNumEntries << std::endl;
  
 for(int i = 0; i < (int)pIPAddrTable->dwNumEntries; i++) 
 {   
  std::cout << "\n\tInterface Index[" << i << "]:\t" << pIPAddrTable->table[i].dwIndex << std::endl;

  IN_ADDR IPAddr;

  IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwAddr;
  std::cout << "\tIP Address[" << i << "]:     \t" << inet_ntoa(IPAddr) << std::endl;

  IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwMask;
  std::cout << "\tSubnet Mask[" << i << "]:    \t" << inet_ntoa(IPAddr) << std::endl;

  IPAddr.S_un.S_addr = (u_long) pIPAddrTable->table[i].dwBCastAddr;
  std::cout << "\tBroadCast[" << i << "]:      \t" << inet_ntoa(IPAddr) << "(" << pIPAddrTable->table[i].dwBCastAddr << ")" << std::endl;
  std::cout << "\tReassembly size[" << i << "]:\t" << pIPAddrTable->table[i].dwReasmSize << std::endl;

  std::cout << "\tType and State[" << i << "]:";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_PRIMARY)
   std::cout << "\tPrimary IP Address";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_DYNAMIC)
   std::cout << "\tDynamic IP Address";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_DISCONNECTED)
   std::cout << "\tAddress is on disconnected interface";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_DELETED)
   std::cout << "\tAddress is being deleted";

  if(pIPAddrTable->table[i].wType & MIB_IPADDR_TRANSIENT)
   std::cout << "\tTransient address";

  std::cout << std::endl;

  if(IP_LOCALHOST == pIPAddrTable->table[i].dwAddr)
  {
   std::cout << "\tLOCALHOST interface" << std::endl;
   // continue;
  }
    
  MIB_IFROW iInfo;
  memset(&iInfo, 0, sizeof(MIB_IFROW));
  iInfo.dwIndex = pIPAddrTable->table[i].dwIndex;
  GetIfEntry(&iInfo);

  std::cout << "\tNetwork interface name: " << iInfo.bDescr << std::endl;

  std::cout << "\tNetwork interface type: ";

  switch(iInfo.dwType)
  {
  case MIB_IF_TYPE_OTHER:
   std::cout << "OTHER" << std::endl;
   break;
  case MIB_IF_TYPE_ETHERNET:
   std::cout << "ETHERNET" << std::endl;
   break;
  case MIB_IF_TYPE_TOKENRING:
   std::cout << "TOKENRING" << std::endl;
   break;
  case MIB_IF_TYPE_FDDI:
   std::cout << "FDDI" << std::endl;
   break;
  case MIB_IF_TYPE_PPP:
   std::cout << "PPP" << std::endl;
   break;
  case MIB_IF_TYPE_LOOPBACK:
   std::cout << "LOOPBACK" << std::endl;
   break;
  case MIB_IF_TYPE_SLIP:
   std::cout << "SLIP" << std::endl;
   break;
  }

  const int unMACSegmentsCount = 6;

  if(unMACSegmentsCount == iInfo.dwPhysAddrLen)
  {      
   std::ostringstream ossMAC;
   ossMAC.fill('0');
   
   ossMAC << std::setw(2) << std::hex << static_cast<unsigned int>(iInfo.bPhysAddr[0]);

   for(int i = 1; i < unMACSegmentsCount; i++)
   {
    ossMAC << '-' << std::setw(2) << std::hex << static_cast<unsigned int>(iInfo.bPhysAddr[i]);
   }
    
   std::cout << "\tMAC Address:            " << ossMAC.str() << std::endl;   
  }  

  std::cout << std::endl;
 } 

 if (pIPAddrTable) 
 {
  free(pIPAddrTable);
  pIPAddrTable = 0;
 }
}

unsigned __stdcall thfn(void* args)
{
 HANDLE hTerminateEvent = *(HANDLE*)args;
 BOOL bTerminate = FALSE;
 
 OVERLAPPED overlap;
 overlap.hEvent = WSACreateEvent();

 if(overlap.hEvent == WSA_INVALID_EVENT)
 {
  std::cout << "WSACreateEvent() failed. Error code: " << WSAGetLastError() << std::endl;
  return THREAD_RETURN_CODE_ERROR;
 }

 while(!bTerminate)
 { 
  
  HANDLE h = 0;

  // call NotifyAddrChange in synchronous mode
  DWORD dwRetVal = NotifyAddrChange(&h, &overlap);

  if(dwRetVal != ERROR_IO_PENDING)
  {
   std::cout << "NotifyAddrChange() failed. Error code: " << WSAGetLastError() << std::endl;
   break;
  }

  HANDLE waitObjects[2] = {hTerminateEvent, overlap.hEvent};

  std::cout << "\nWaiting for IP Table change or termination request..." << std::endl;

  dwRetVal = WaitForMultipleObjects(2, waitObjects, FALSE, INFINITE);

  switch(dwRetVal)
  {
  case WAIT_OBJECT_0:
   std::cout << "WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 (hTerminateEvent is signaled)" << std::endl;
   bTerminate = TRUE;
   break;
  case WAIT_OBJECT_0 + 1:
   std::cout << "WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 + 1 (overlap.hEvent is signaled)" << std::endl;   
   
   if(!WSAResetEvent(overlap.hEvent))
   {
    std::cout << "WSAResetEvent() failed. Error code: " << WSAGetLastError() << std::endl;
    bTerminate = TRUE;
    break;
   }

   PrintIPTable();
   break;
  case WAIT_FAILED:
   std::cout << "WaitForSingleObject(waitObjects) returned WAIT_FAILED (function failed)" << std::endl;
   bTerminate = TRUE;
   break;
  }  
 }
 
 if(!WSACloseEvent(overlap.hEvent))
 {
  std::cout << "WSACloseEvent() failed. Error code: " << WSAGetLastError() << std::endl;
  return THREAD_RETURN_CODE_ERROR;
 }

 return THREAD_RETURN_CODE_SUCCESS;
}

void WaitUserInput()
{
 std::cin.clear(); 
 std::cin.ignore(1, '\n');
}

// NOTE: std::cout is shared between two threads and is not thread safe!
int main(int argc, char* argv[])
{
// std::cout << "main()" << std::endl;

 HANDLE hTerminateEvent = CreateEvent(0, TRUE, FALSE, 0);

 if(!hTerminateEvent)
 {
  std::cout << "CreateEvent() failed. Error code: " << GetLastError() << std::endl;
  return APP_RETURN_CODE_ERROR;
 }

 unsigned unThreadID = 0;
 HANDLE hThread = 0;

// std::cout << "Creating thread..." << std::endl;
 hThread = (HANDLE) _beginthreadex(0, 0, thfn, &hTerminateEvent, 0, &unThreadID);

 if(!hThread)
 {
  std::cout << "_beginthreadex() failed. Error code: " << errno << std::endl;
  return APP_RETURN_CODE_ERROR;
 }

 // (not reliable way to) make sure child thread has started before main thread continues
 Sleep(1000);

// std::cout << "Created thread with ID: " << unThreadID << std::endl;

 std::cout << "Press ENTER to terminate listening for changes in IP address table..." << std::endl;
 WaitUserInput();

 SetEvent(hTerminateEvent);

 // wait for thread to terminate
 DWORD dwRetVal = WaitForSingleObject(hThread, INFINITE);

 switch(dwRetVal)
 {
 case WAIT_OBJECT_0:
  std::cout << "WaitForSingleObject(hThread) returned WAIT_OBJECT_0 (event is signaled)" << std::endl;
  break;
 case WAIT_TIMEOUT:
  std::cout << "WaitForSingleObject(hThread) returned WAIT_TIMEOUT (timeout elapsed; event is nonsignaled)" << std::endl;
  break;
 case WAIT_FAILED:
  std::cout << "WaitForSingleObject(hThread) returned WAIT_FAILED (function failed)" << std::endl;
  break;
 }

 if(!CloseHandle(hThread))
 {
  std::cout << "CloseHandle() failed. Error code: " << GetLastError() << std::endl;
  return APP_RETURN_CODE_ERROR;
 }

 std::cout << "Press ENTER to exit..." << std::endl;
 WaitUserInput();

// std::cout << "~main()" << std::endl;
 return APP_RETURN_CODE_SUCCESS;
}

This is the output if we unplug network cable and then plug it back again:


Waiting for IP Table change or termination request...
Press ENTER to terminate listening for changes in IP address table...
WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 + 1 (overlap.hEvent is s
ignaled)
Num Entries: 2

Interface Index[0]: 17
IP Address[0]: 192.168.56.1
Subnet Mask[0]: 255.255.255.0
BroadCast[0]: 1.0.0.0(1)
Reassembly size[0]: 65535
Type and State[0]: Primary IP Address
Network interface name: VirtualBox Host-Only Ethernet Adapter
Network interface type: ETHERNET
MAC Address: 08-00-27-00-68-56


Interface Index[1]: 1
IP Address[1]: 127.0.0.1
Subnet Mask[1]: 255.0.0.0
BroadCast[1]: 1.0.0.0(1)
Reassembly size[1]: 65535
Type and State[1]: Primary IP Address
LOCALHOST interface
Network interface name: Software Loopback Interface 1
Network interface type: LOOPBACK


Waiting for IP Table change or termination request...
WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 + 1 (overlap.hEvent is s
ignaled)
Num Entries: 3

Interface Index[0]: 10
IP Address[0]: 192.168.253.122
Subnet Mask[0]: 255.255.255.0
BroadCast[0]: 1.0.0.0(1)
Reassembly size[0]: 65535
Type and State[0]: Primary IP Address Dynamic IP Address
Network interface name: Intel(R) 82566DC Gigabit Network Connection
Network interface type: ETHERNET
MAC Address: 00-19-d1-1b-e0-88


Interface Index[1]: 17
IP Address[1]: 192.168.56.1
Subnet Mask[1]: 255.255.255.0
BroadCast[1]: 1.0.0.0(1)
Reassembly size[1]: 65535
Type and State[1]: Primary IP Address
Network interface name: VirtualBox Host-Only Ethernet Adapter
Network interface type: ETHERNET
MAC Address: 08-00-27-00-68-56


Interface Index[2]: 1
IP Address[2]: 127.0.0.1
Subnet Mask[2]: 255.0.0.0
BroadCast[2]: 1.0.0.0(1)
Reassembly size[2]: 65535
Type and State[2]: Primary IP Address
LOCALHOST interface
Network interface name: Software Loopback Interface 1
Network interface type: LOOPBACK


Waiting for IP Table change or termination request...

WaitForSingleObject(waitObjects) returned WAIT_OBJECT_0 (hTerminateEvent is sign
aled)
WaitForSingleObject(hThread) returned WAIT_OBJECT_0 (event is signaled)
Press ENTER to exit...