Linux port based routing - linux

I have a requirement to host a java application on a server which can simulate multiple devices each one with separate IP address. The scalability requirements are so large that I cannot think of launching VMs or any containers.
The way I thought about supporting this is to have the application listen on a particular port on 127.0.0.1 , add a route to forward all the packets destined to say 192.168.0.1/24 (internal addresses where clients connected to my server will send packets) forward to 127.0.0.1:
Is this the best way of implementing or any other better options available.

You can create multiple loopback interface, in addition to 127.0.0.1, you can create a loopback interface on 127.0.0.2, 127.0.0.3, etc... Each one of them will be a loopback interface of its own.
ifconfig tells you:
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 0 (Local Loopback)
RX packets 353847 bytes 99880673 (95.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 353847 bytes 99880673 (95.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Note that the netmask is 255.0.0.0

Related

DNS lookup failing over ethernet but not USB

I currently have two different 5g routers. My PC's wifi doesn't work, so I'm only able to connect either of them through wired connection. The old one that I want to get rid of uses a usb, and works. The new one uses ethernet, and fails with DNS lookup (ping www.google.com fails but ping 8.8.8.8 succeeds.)
resolve.conf looks like:
# Generated by NetworkManager
search lan
nameserver 192.168.1.1
nameserver fe80::d4bb:5cff:fe4e:6313
nameserver fe80::38:40ff:fe30:419e
# NOTE: the libc resolver may not support more than 3 nameservers.
# The nameservers listed below may not be recognized.
nameserver fe80::34e1:ffff:fe65:f72b
nameserver fe80::d43f:21ff:fe59:462a
nameserver 192.168.12.1
nameserver fe80::ca99:b2ff:fee7:71f5%enp5s0
nameserver fe80::d43f:21ff:fe59:462a%enp6s0f1u1
nmcli yields:
enp5s0: connected to Wired connection 1
"Intel I211"
ethernet (igb), 3C:7C:3F:1E:C6:01, hw, mtu 1500
ip4 default, ip6 default
inet4 192.168.12.232/24
route4 192.168.12.0/24 metric 100
route4 default via 192.168.12.1 metric 100
inet6 2607:fb90:3307:6e5d:91df:e64b:949:c78c/128
inet6 2607:fb90:3307:6e5d:bcb3:1b35:1589:bd17/64
inet6 fe80::48f9:3fb0:7e83:d1a7/64
route6 2607:fb90:3307:6e5d:91df:e64b:949:c78c/128 metric 100
route6 2607:fb90:3307:6e5d::/64 metric 100
route6 fe80::/64 metric 1024
route6 default via fe80::ca99:b2ff:fee7:71f5 metric 100
enp6s0f1u1: connected to Wired connection 2
"Novatel Wireless M2000"
ethernet (rndis_host), 00:15:FF:30:51:72, hw, mtu 1428
inet4 192.168.1.5/24
route4 192.168.1.0/24 metric 101
route4 default via 192.168.1.1 metric 101
inet6 2607:fb90:3395:673a:5552:7f52:abd9:488e/64
inet6 fe80::20b0:4b16:c9f:e9d0/64
route6 fe80::/64 metric 1024
route6 2607:fb90:3395:673a::/64 metric 101
route6 default via fe80::d43f:21ff:fe59:462a metric 101
"Wired connection 2" is the one that works (the USB one.)
So I'm pretty clear that my resolv.conf is specifically telling the usb interface to use one DNS server (fe80::d43f:21ff:fe59:462a) that works, and telling the ethernet interface to use another (fe80::ca99:b2ff:fee7:71f5) that fails. I just don't know why it's doing that, or how to make it stop (given that I think NetworkManager generates that file, and will presumably re-generate it if I just edit it myself.)
What happen? What do?

How to connect to MongoDB from WSL2

I started a MongoDB server mongod.exe on my local Win11 machine and want to connect to it with pymongo from within WSL2 (from a Jupyter Notebook started in WSL2; ip address taken from ifconfig below):
import pymongo as pm
import datetime as dt
host = 'mongodb://192.168.72.32'
port = 27017
client = pm.MongoClient(host, port)
client.admin.command('ismaster')
I keep on getting a ServerSelectionTimeoutError: 192.168.72.32:27017: [Errno 111] Connection refused error.
The problem is how to expose the server/port from Windows to WSL2. I already opened ports in netsh (as described in official docs here). Output from ifconfig on WSL2 end:
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.72.32 netmask 255.255.240.0 broadcast 192.168.79.255
inet6 fe80::215:5dff:fe96:9d57 prefixlen 64 scopeid 0x20<link>
ether 00:15:5d:96:9d:57 txqueuelen 1000 (Ethernet)
RX packets 662495 bytes 168890186 (168.8 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 170242 bytes 369162848 (369.1 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 99019 bytes 163040786 (163.0 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 99019 bytes 163040786 (163.0 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
What am I doing wrong?
There are (at least) three things that need to be in place to access any network application/service running in Windows from WSL2:
*Configure the service to listen on the correct Windows network interface (not localhost), a.k.a. the "bind address".
Open the necessary firewall port(s)
Use the correct address from WSL2 (again, not localhost)
You may just be missing the first part, as MongoDB binds to localhost by default. According to the doc:
MongoDB binaries, mongod and mongos, bind to localhost by default. If the net.ipv6 configuration file setting or the --ipv6 command line option is set for the binary, the binary additionally binds to the localhost IPv6 address.
More detail provided below on each of these requirements (mostly copied, with some slight tweaks for your particular use-case, from my related answer on Super User):
Bind address
Many applications or services default to binding to localhost, which (obviously) means that you can only connect to them from the host on which the service is running. Because WSL2 runs on a "separate network", you won't be able to access a service in Windows that is listening only on localhost. You'll probably want to bind to 0.0.0.0 (for IPv4) and/or :: (for IPv6) to listen on all interfaces.
The method of configuring the service will, of course, vary for different applications, but usually you'll find the setting labeled something like "Bind Address", "Listen On", or something similar. Instructions for MongoDB specifically are linked above.
Make sure to restart the application/service after changing this setting.
Side note: It's possible to bind only to the WSL2 interface as I describe in this answer (buried somewhere in the middle), but it's probably overkill, as the firewall can be used more easily to block connections from non-WSL networks if desired.
Firewall configuration
By default, Windows Defender Firewall (and others) will block incoming connections to the host from another network. Since we've already established that WSL2 is running in a separate network, you'll need to open a firewall port for your service.
You can do this selectively from PowerShell (in an Administrative shell) with something like:
New-NetFirewallRule -DisplayName "MongoDB from WSL2" -InterfaceAlias "vEthernet (WSL)" -Direction Inbound -Protocol TCP -LocalPort 27017 -Action Allow
Of course, you can drop either:
the InterfaceAlias, in which case it will open 8545 from all networks
or the LocalPort, in which case it will act like the "disable" option above and always accept incoming traffic from the WSL network interface.
Finding the correct Windows address to use from WSL2
There are several methods (and IP addresses) you can use. The easiest way is simply to use the IP address of the Windows host, if you know it. However, if it is dynamically assigned and changes frequently (which is, I believe, fairly unusual nowaways), then you may need to change your WSL2 code each reboot.
In your case, it looks like you likely have a static address in the 192.168.0.0/32 private address space, so you may not need the following.
However, it's probably best practice anyway to use a mDNS name that will (usually) resolve correctly for static or dynamic address assignments.
Assuming that you haven't overridden the default /etc/resolv.conf that WSL generates, this can be done by taking the Windows computer name and simply appending .local. For instance, if your computer name is bubblegum, then bubblegum.local should be the correct address.
From Python, this can be obtained with:
import socket
server = f'{socket.gethostname()}.local' # Generic form
host = f'mongodb://{socket.gethostname()}.local' # For your example
You should find that this is the same address as found with:
echo $(ip route list default | awk '{print $3}')
If, however, you have overridden the /etc/resolv.conf (necessary in some cases due to VPNs or other networking configurations), then you may need something more complicated like:
echo $(host `hostname --long` | grep -oP '(\s)\d+(\.\d+){3}' | tail -1 | awk '{ print $NF }' | tr -d '\r')
(Credit to #ChaiAng's answer on Ask Ubuntu for this method).
However, note that it is substantially slower than mDNS.

Python 3 - Cannot receive IPv6 packets (UDP - linux)

I have a script that is trying to receive IPv6 packets, but it fails to receive any.
First off, here is my ethernet configuration from ifconfig.
eth1 Link encap:Ethernet HWaddr f8:b1:56:9a:cf:ef
inet addr:192.168.1.90 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::fab1:56ff:fe9a:cfef/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:751359199 errors:38 dropped:10874 overruns:0 frame:35
TX packets:23407 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:1033523557150 (1.0 TB) TX bytes:2002869 (2.0 MB)
Interrupt:20 Memory:ef400000-ef420000
I have two network cards, but am using one for internet and one for testing. The second card is connect to a device that sends ethernet packets. I am configuring that device to send IPv6 packets to address fe80::fab1:56ff:fe9a:cfef and port 46780 (however, I can configure it to send to any IPv6 address and any port). I wrote a python script to receive these packets, but I either get an error, or my script doesn't find the packets. I confirmed these packets through wireshark, and through using a raw python socket.
Here is a list of things I have tried and the various errors/problems I encounter.
If I bind to address "::1", I am able to bind to the address. However, I never receive any IPv6 packets.
I tried using socket.getaddrinfo() and then use the returned information and bind to that, however when I try to do so I get the error "Invalid argument"
info = socket.getaddrinfo(host_ipv6_addr, port_num, socket.AF_INET6,
socket.SOCK_DGRAM, 0, socket.AI_PASSIVE)
rtp_socket.bind(info[0][4])
socket.getaddrinfo returns [(10, 2, 17, '', ('fe80::fab1:56ff:fe9a:cfef', 46780, 0, 0))]
If I try to bind directly to my IPv6 address, I also received "Invalid argument". However, when I changed the scope from 0 to 5, I instead received the error "Cannot assign request address".
rtp_socket.bind( (host_ipv6_addr, port_num, 0, 5))
Any insight would be greatly appreciated. I'm guessing at this point that I don't have my ethernet card setup properly or something.
UPDATE:
Using Michael Hampton's answer, I solved my problem by using the information from socket.getaddrinfo with the IP address being "fe80::fab1:56ff:fe9a:cfef%eth1" and sticking the results into rtp_socket.bind(). The scope ID went from 0 to 3.
You're trying to bind to a link-local address but you have forgotten to include the scope ID (in this case, %eth1).
So you should be binding to address fe80::fab1:56ff:fe9a:cfef%eth1.

dhcpv6 returning bad subnet

I have IPv6 on a linux machine and my network and it works. Now I want to set up DHCP for it. I set up the isc-dhcp-server and configured the subnet.
Another linux machine (both debian 7) acts as test-client and gets the IP, but not in the range configured, and, much worse, gets a /64 subnet and not a /80.
Since the IP pool available on the router is already a subset of the /64 assigned to another upstream-machine, I need a smaller subnet. I cannot allow it to be /64.
Config of dhcp server:
subnet6 2a01:4f8:202:6106:acda::/80 {
range6 2a01:4f8:202:6106:acda:f000::/84;
option dhcp6.name-servers 2a01:4f8:202:6106::2;
prefix6 2a01:4f8:202:6106:acda:c000:: 2a01:4f8:202:6106:acda:f000:: /84;
}
ifconfig output on client:
debian#arm:~$ sudo ifconfig
[sudo] password for debian:
eth0 Link encap:Ethernet HWaddr c8:a0:30:ae:48:24
inet addr:192.168.0.104 Bcast:192.168.0.255 Mask:255.255.255.0
inet6 addr: fe80::caa0:30ff:feae:4824/64 Scope:Link
inet6 addr: 2a01:4f8:202:6106:acda:ff2f:452c:b7b5/64 Scope:Global
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:185 errors:0 dropped:0 overruns:0 frame:0
TX packets:201 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:18222 (17.7 KiB) TX bytes:23159 (22.6 KiB)
Interrupt:56
A windows-7 machine also connected does not get an IPv6 address at all.
config of the radvd on the server (in case it matters)
interface eth0 {
AdvSendAdvert on;
prefix 2a01:4f8:202:6106:acda::/80 {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr on;
};
route 2000::/3
{
};
};
What's wrong? Why is this not working? Is the bad subnet-size a bug in the server? Or the client?
Result of the bad subnet-size is that for example the nameserver, 2a01:4f8:202:6106::2 , in the 64-bit range, is not reachable. The client thinks it should be on the lan segment and tries to get the link-local IPv6 and the ethernet MAC of it and fails. It needs to go via the router. When I set the subnet manually to /80 everything works fine.
First of course the general warning: using non-/64 subnet sizes will break things. Your ISP should really give you a decent amount of address space to work with, like a /48 or a /56. You can then route /64s out of that wherever you want.
Then you have to look at how your ISP gives you your current /64. If they route it to a LAN that is connected to your server's eth0 interface then there is nothing much you can do except bridging or proxy-ND because you have to make it look like everything is directly connected to that LAN. Both methods have their own complications.
If you are bridging to a LAN managed by your ISP then you shouldn't run anything like radvd or dhcpd because you'll interfere with your ISP.
If you are using proxy-ND or your ISP routes the /64 to your server (so you have a different IPv6 address on your server's interface to the ISP and the ISP routes the /64 to that interface) then you should indeed run radvd and dhcpd but only on the internal interface, not towards your ISP.
Back to your RA+DHCPv6 setup because that part of your question is easy to answer. There are three things wrong with your radvd setup (so, yes, it matters a lot :)
First you cannot do SLAAC (StateLess Address Auto Configuration) on anything except a /64 so you'll have to turn AdvAutonomous off. Then you have to tell the clients that a managed (stateful) DHCPv6 server is available so turn the AdvManagedFlag on. And the route 2000::/3 is also unnecessary. You are advertising that you are the default gateway and this more-specific doesn't add anything useful.
interface eth1 {
AdvSendAdvert on;
AdvManagedFlag on;
prefix 2a01:4f8:202:6106:acda::/80 {
AdvOnLink on;
AdvAutonomous off;
AdvRouterAddr on;
};
};

ffmpeg with double ethernet interfaces works wrong

A server with double interfaces.
One(eht0) is used for WAN which provides http/ssh services for internet users.
The other(eth1) is used to receive multicast data from intranet.
218.108.132.177 is public network gateway.
125.210.198.1 is private network gateway.
233.49.3.*/24 is multicast address.
10.0.11.*/24 is the source of multicast data.
When the route table is like below, ffmpeg can't read the udp data from eth1, ffmpeg hung up:
rrca#rcasnap02:~$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
218.108.132.176 * 255.255.255.252 U 0 0 0 eth0
125.210.198.0 * 255.255.255.240 U 0 0 0 eth1
default 218.108.132.177 0.0.0.0 UG 100 0 0 eth0
default 125.210.198.1 0.0.0.0 UG 100 0 0 eth1
or
rrca#rcasnap02:~$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
218.108.132.176 * 255.255.255.252 U 0 0 0 eth0
125.210.198.0 * 255.255.255.240 U 0 0 0 eth1
default 218.108.132.177 0.0.0.0 UG 100 0 0 eth0
10.0.11.0 125.210.198.1 0.0.0.0 UG 100 0 0 eth1
or
rrca#rcasnap02:~$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
218.108.132.176 * 255.255.255.252 U 0 0 0 eth0
125.210.198.0 * 255.255.255.240 U 0 0 0 eth1
default 218.108.132.177 0.0.0.0 UG 100 0 0 eth0
233.49.3.0 125.210.198.1 255.255.255.0 UG 100 0 0 eth1
I want to the ffmpeg work right,but now I think the two default route in route table disturb eachother, and I take a try, when the public gateway route is deleted, or the private gateway route is at the head of public default gateway route, ffmpeg works well, I think it read multicast from eth1.But the route table is not thus, ffmpeg can't read data from eth1, I think it read data on eth0(which is not private network interface).
How to do ffmpeg works well with two interfaces at the same time?
You need to configure the correct route for multicast traffic. The kernel does an origin check on all incoming multicast traffic: if it arrives on a different interface from the one it would use to send such traffic it's dropped.
Just set a route for multicast on your eth1 interface:
# route add -net 224.0.0.0/8 dev eth1
Alternatively, disable the origin checking:
# echo 0 > /proc/sys/net/ipv4/conf/eth1/rp_filter
While the answer is correct in that a route is required, I had to route 224.0.0.0/4 (which includes up to 239.255.255.255) as my device was sending the video stream to 239.255.42.42

Resources