docked flask / waitress.serve not visible in local network - docker

I have my server running under docker and start it with the command serve(app, listen='*:5000').
I can:
access it in container under both 127.0.0.1:5000 amd localhost:5000
access it from outside the container under localhost:5000
I cannot:
access it from outside container under '127.0.0.1:5000'
access it from local network using local ip (and this is what matters the most to me)
I was trying to pass the local address into the serve command but it throws error saying that the address cannot be accessed. Also tried the host='0.0.0.0'. Did not help.
Would anyone know how to make it visible outside of my machine?

ok so i found a solutions that seems to do the trick. the problem was wsl.
at github wsl repo there is a script that sets a bridge.
below i post the code so it does not perish.
credit to edwindijas
$found = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
if( $found ){
$remoteport = $matches[0];
} else{
echo "The Script Exited, the ip address of WSL 2 cannot be found";
exit;
}
#[Ports]
#All the ports you want to forward separated by coma
$ports=#(80,443,10000,3000,5000);
#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join ",";
#Remove Firewall Exception Rules
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";
#adding Exception Rules for inbound and outbound Rules
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $ports_a -Action Allow -Protocol TCP";
for( $i = 0; $i -lt $ports.length; $i++ ){
$port = $ports[$i];
iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport";
}

If you have not already done so, try exposing port 5000.
This can be done by adding
EXPOSE 5000
to your Dockerfile. You will also need to have host='0.0.0.0' in your serve in order to be able to access your page from the local network.

Related

TPROXY compatibility with Docker

I'm trying to understand how TPROXY works in an effort to build a transparent proxy for Docker containers.
After lots of research I managed to create a network namespace, inject an veth interface into it and add TPROXY rules. The following script worked on a clean Ubuntu 18.04.3:
ip netns add ns0
ip link add br1 type bridge
ip link add veth0 type veth peer name veth1
ip link set veth0 master br1
ip link set veth1 netns ns0
ip addr add 192.168.3.1/24 dev br1
ip link set br1 up
ip link set veth0 up
ip netns exec ns0 ip addr add 192.168.3.2/24 dev veth1
ip netns exec ns0 ip link set veth1 up
ip netns exec ns0 ip route add default via 192.168.3.1
iptables -t mangle -A PREROUTING -i br1 -p tcp -j TPROXY --on-ip 127.0.0.1 --on-port 1234 --tproxy-mark 0x1/0x1
ip rule add fwmark 0x1 tab 30
ip route add local default dev lo tab 30
After that I launched a toy Python server from Cloudflare blog:
import socket
IP_TRANSPARENT = 19
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.IPPROTO_IP, IP_TRANSPARENT, 1)
s.bind(('127.0.0.1', 1234))
s.listen(32)
print("[+] Bound to tcp://127.0.0.1:1234")
while True:
c, (r_ip, r_port) = s.accept()
l_ip, l_port = c.getsockname()
print("[ ] Connection from tcp://%s:%d to tcp://%s:%d" % (r_ip, r_port, l_ip, l_port))
c.send(b"hello world\n")
c.close()
And finally by running ip netns exec ns0 curl 1.2.4.8 I was able to observe a connection from 192.168.3.2 to 1.2.4.8 and receive the "hello world" message.
The problem is that it seems to have compatibility issues with Docker. All worked well in a clean environment, but once I start Docker things start to go wrong. It seems like the TPROXY rule was no longer working. Running ip netns exec ns0 curl 192.168.3.1 gave "Connection reset" and running ip netns exec ns0 curl 1.2.4.8 timed out (both should have produced the "hello world" message). I tried restoring all iptables rules, deleting ip routes and rules generated by Docker and shutting down Docker, but none worked even if I didn't configure any networks or containers.
What is happening behind the scenes and how can I get TPROXY working normally?
I traced all processes created by Docker using strace -f dockerd, and looked for lines containing exec. Most commands are iptables commands, which I have already excluded, and the lines with modprobe looked interesting. I loaded these modules one by one and figured out that the module causing the trouble is br_netfilter.
The module enables filtering of bridged packets through iptables, ip6tables and arptables. The iptables part can be disabled by executing echo "0" | sudo tee /proc/sys/net/bridge/bridge-nf-call-iptables. After executing the command, the script worked again without impacting Docker containers.
I am still confused though. I haven't understood the consequences of such a setting. I enabled packet tracing, but it seems that the packets matched the exact same set of rules before and after enabling bridge-nf-call-iptables, but in the former case the first TCP SYN packet got delivered to the Python server, in the latter case the packet got dropped for unknown reasons.
Try running docker with -p 1234
"By default, when you create a container, it does not publish any of its ports to the outside world. To make a port available to services outside of Docker, or to Docker containers which are not connected to the container’s network, use the --publish or -p flag."
https://docs.docker.com/config/containers/container-networking/

Cannot connect to Go GRPC server running in local Docker container

I have a go grpc service. I'm developing on a mac, sierra. When running a grpc client against the service locally, all is well, but when running same client against same service in the docker container I get this error:
transport: http2Client.notifyError got notified that the client transport was broken EOF.
FATA[0000] rpc error: code = Internal desc = transport is closing
this is my docker file:
FROM golang:1.7.5
RUN mkdir -p /go/src/github.com/foo/bar
WORKDIR /go/src/github.com/foo/bar
COPY . /go/src/github.com/foo/bar
# ONBUILD RUN go-wrapper download
RUN go install
ENTRYPOINT /go/bin/bar
EXPOSE 51672
my command to build the image:
docker build -t bar .
my command to launch the docker container:
docker run -p 51672:51672 --name bar-container bar
Other info:
client program runs fine from within the docker container
connecting to a regular rest endpoint works fine (http2, grpc related?)
running the lsof command in OS X yields these results
$lsof -i | grep 51672
com.docke 984 oldDave 21u IPv4 0x72779547e3a32c89 0t0 TCP *:51672 (LISTEN)
com.docke 984 oldDave 22u IPv6 0x72779547cc0fd161 0t0 TCP localhost:51672 (LISTEN)
here's a snippet of my server code:
server := &Server{}
endpoint := "localhost:51672"
lis, err := net.Listen("tcp", endpoint)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer(grpc.Creds(creds))
pb.RegisterExpServiceServer(s, server)
// Register reflection service on gRPC server.
reflection.Register(s)
log.Info("Starting Exp server: ", endpoint)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
When you specify a hostname or IP address​ to listen on (in this case localhost which resolves to 127.0.0.1), then your server will only listen on that IP address.
Listening on localhost isn't a problem when you are outside of a Docker container. If your server only listens on 127.0.0.1:51672, then your client can easily connect to it since the connection is also made from 127.0.0.1.
When you run your server inside a Docker container, it'll only listen on 127.0.0.1:51672 as before. The 127.0.0.1 is a local loopback address and it not accessible outside the container.
When you fire up the docker container with "-p 51672:51672", it'll forward traffic heading to 127.0.0.1:51672 to the container's IP address, which in my case is 172.17.0.2.
The container gets an IP addresses within the docker0 network interface (which you can see with the "ip addr ls" command)
So, when your traffic gets forwarded to the container on 172.17.0.2:51672, there's nothing listening there and the connection attempt fails.
The fix:
The problem is with the listen endpoint:
endpoint := "localhost:51672"
To fix your problem, change it to
endpoint := ":51672"
That'll make your server listen on all it container's IP addresses.
Additional info:
When you expose ports in a Docker container, Docker will create iptables rules to do the actual forwarding. See this. You can view these rules
with:
iptables -n -L
iptables -t nat -n -L
If you use docker container to run grpc service,you should make sure grpc service and grpc client on ths same bridge
if you are using docker container, u can define network by IP and give this IP to your IP address(like: 178.20.0.5).

How to change Freeradius3 default port(auth1812 & Account1813)

I am using freeradius3.0.4. I need to change the default port(1812,1813) to 18120 and 18130. I don't know where it is. Please help! there is no port setting in the main conf.
Change the port under /etc/service.
This is what I get on freeRADIUS Version 3.0.16:
$ sudo freeradius -X -i 0.0.0.0 -p 1850
radiusd: #### Opening IP addresses and Ports ####
Listening on auth address * port 1850
Listening on acct address * port 1851
Listening on proxy address * port 56033
Ready to process requests
From man freeradius:
-p port
Defines which port is used for receiving authentication packets. Accounting packets are received on "port + 1".
When this command-line option is given, all "listen" sections in radiusd.conf are ignored.
This option MUST be used in conjunction with "-i".
So if you'd like to make the changes permanent, it seems that you need to add a "listen" section to your configuration file with the appropriate parameters (didn't have time to look up the exact syntax).
Also note the constraint that the accounting port is always going to be the authentication port plus one. If you really must modify this behavior on freeRADIUS you might have to change the source code and build your own version.
The port number is defined in /etc/freeradius/3.0/sites-enabled/default:
server default {
listen {
type = auth
ipaddr = *
port = 0
limit {
max_connections = 16
lifetime = 0
idle_timeout = 30
}
}
listen {
ipaddr = *
port = 0
type = acct
limit {
}
}
... more configuration
}
As you can see the configured port is 0. This just means it'll use the FreeRADIUS default port which is 1812/1813 (auth/acct).
If you want to change these port numbers, change them in the above file and run systemctl restart freeradius
If you want to run 2 RADIUS sessions in parallel you'd have to cp -rp /etc/freeradius /etc/freeradius2 and start a second RADIUS process with freeradius -X -d /etc/freeradius2
Hope I could help, I also had this issue
Edits:
0 means that it will use the port defined in /etc/services (by default is 1812)
Instead of freeradius -X -c ... use freeradius -X -d ... to use a custom directory
Use cp -rp ... because otherwise the permissions would change and FreeRADIUS wouldn't work anymore

Can't bind to port 80

I'm using Windows 10 and Visual Studio 2016. I can't bind to port 80. I can bind to all other ports. The error printed is: "Bind of IP address 0.0.0.0 returned an error, port 80: No error"
Here is my code:
/* bind this socket to the server's Internet address */
if( bind(fd,(struct sockaddr *)server_addr,sizeof(struct sockaddr_in))<0 )
{
printf("Bind of IP address %s returned an error, port %d: %s\n",
inet_ntoa(server_addr->sin_addr), ntohs(server_addr->sin_port),
strerror(errno));
//close(fd);
return -1;
}
Use "netstat -o -q -a -n". Then use task manager and look at the Details tab. Click to sort the PID as low to high. Find the PID and notice the name of the program that has the port open. In my case System is listening on port 80 and since you can't kill System then you basically can't bind to port 80.
Well, you can use netstat to see if anyone else is listening, see this article:
https://technet.microsoft.com/en-us/library/bb490947.aspx
Find which process is already using port 80 and stop it.
You also need to be an admin or explicitly grant access to the user you're running as if you're binding port < 1024. See here
HttpListener Access Denied

Expect Script: Parse Specific Info From Cisco CLI

I'm new to Expect scripting, and trying to parse Cisco router ACL output.
I'm specifically trying to parse IP addresses between the first 2 remark lines. Any help greatly appreciated.
Here's one of my random attempts. It parses IP addresses from the ACL, but doesn't stop at the 2nd remark line:
send "show run | section ip access-list extended OUTSIDE\r\n"
set ip {}
expect {
"remark ##### DENIED HOSTS #####\r\n" {
expect -re {(\d+\.\d+\.\d+\.\d+)} {
set ip "${ip}$expect_out(0,string)"
puts $ip
set ip {}
exp_continue
}
}
}
Not only does the script not stop at the 2nd remark line like I want it to, but it doesn't seem to have an exit point and waits for Expect to timeout.
Random sample ACL for reference:
ip access-list extended OUTSIDE
remark ##### DENIED HOSTS #####
deny ip host 2.2.2.2 any
deny ip host 9.9.9.9 any
deny ip host 8.7.6.5 any
deny ip host 5.6.7.8 any
deny ip host 5.5.5.5 any
deny ip host 4.4.4.4 any
deny ip host 3.3.3.3 any
remark ########################
permit tcp any any eq 22
deny ip any any
permit ip host 2.3.5.1 any
I basically want to parse addresses from 2.2.2.2 to 3.3.3.3, but then exit once the script reaches the 2nd remark line.
With exp_continue, it is always better to add the case where we want to terminate from expect. So that, if the exit case arrived, we can terminate from the expect. Else, obviously timeout will happen.
E.g.
expect{
“p” {send “\r\r\r”; exp_continue}
“+” {incr foo; exp_continue}
“i” {puts "test"; exp_continue}
“quit” exit
}
As you can see, if the word 'quit' comes, then it will be exited.
Lets come to your question. You need to exit from expect when the word
'remark ########################' arrives. But, if we code like,
expect {
"remark ##### DENIED HOSTS #####\r\n" {
expect {
"remark ########################" {exit}
-re {(\d+\.\d+\.\d+\.\d+)} {
set ip "${ip}$expect_out(0,string)"
puts "-->$ip"
set ip {}
exp_continue
}
}
}
}
Program will terminate the expect while the ip parsing is in progress at the middle of anything.
Instead of doing this way, you can better get the whole output and try to parse it as a separate variable, to avoid overhead within expect.
send "show run | section ip access-list extended OUTSIDE\r\n"
expect {
-re {deny\s+ip\s+host\s+(.*)remark} { puts "match found" }
timeout {puts "timeout happened"}
}
Now we have the match and it will be available in the variable expect_out(1,string).
Then we can do regexp in the variable and parse the ip address.
puts [ regexp -inline -all {\d.\d.\d.\d} $expect_out(1,string) ]
You can try one more way as below. Instead of doing regular expression at the expect, you can simply get the whole output and then do the regexp as below.
send "sh run | section ip access-list extended OUTSIDE\r"
#Assuming your router's hostname is `Router`
expect "Router#"
#output will hold the command output.
set output expect_out(buffer)
puts $output
set ip_list [regexp -inline -all {\d.\d.\d.\d} $output]
foreach ip $ip_list {
puts $ip
}
Thanks to Dinesh!!!
Reposting the final working code (or a mix of Dinesh-provided code) here so it's not lost in all the text above (and so I can format more easily than in the comment section).
send "show run | section ip access-list extended OUTSIDE\n"
expect -re {remark(.*)remark}
set output $expect_out(buffer)
#puts $output
puts "\r"
set ip_list [regexp -inline -all {\d.\d.\d.\d} $output]
foreach ip $ip_list {
puts $ip
}
I commented out the 1st puts line, but left it there to use when testing to see what's actually being stored in $output.
Here's the ACL that was parsed from the router CLI:
ip access-list extended OUTSIDE
remark ##### DENIED HOSTS #####
deny ip host 2.2.2.2 any
deny ip host 9.9.9.9 any
deny ip host 8.7.6.5 any
deny ip host 5.6.7.8 any
deny ip host 5.5.5.5 any
deny ip host 4.4.4.4 any
deny ip host 3.3.3.3 any
remark ########################
permit tcp any any eq 22
deny ip host 82.28.82.28 any
permit ip host 2.3.5.1 any
I know, it's a completely convoluted ACL, but it worked great for testing.
Here's Expect script output after parsing the ACL:
2.2.2.2
9.9.9.9
8.7.6.5
5.6.7.8
5.5.5.5
4.4.4.4
3.3.3.3
Any / all IP addresses after the 2nd ACL remark line are ignored as desired!
Thanks Dinesh!
why dont you use perl with Net::Telnet::Cisco ?
https://metacpan.org/pod/Net::Telnet::Cisco

Resources