kill/close client connections to docker from host - bash

I have a problem about connections to a docker containers from outside of my network. Iptables not worked yet for me (See this question).
The container open a connection on port 9010 which maps to its 443:
docker run -d [some other configs] --restart=always -p 9010:443 -p 9010:443/udp xxx/myImage
and I cannot see the client connections to this in my host:
root#ubuntu:~# netstat -anlp | grep ESTABLISHED
tcp 0 64 88.99.126.173:22 191.96.180.79:2543 ESTABLISHED 20855/sshd: root#pt
However I can see it inside container:
root#ubuntu:~# docker exec -it b7772c4d43dc /bin/bash -c 'netstat -anlp | grep ESTABLISHED'
tcp 0 0 ::ffff:172.17.0.2:443 ::ffff:191.96.180.79:3298 ESTABLISHED 7/python
Now I want to close this connection in that container, but since docker is from python:3.6-alpine image, there is not useful commands such as tcpkill command. How I can close this connections by bash inside my host.

Related

Unable to connect to the Docker Container from the host browser on MacOS

I' am trying to deploy docker container on Mac machine. I ran the command:
docker run -P -it clickstream-collector_csapi -c "test_config.yml".
output: ts=2020-02-24T17:25:43Z lvl=info msg="Starting Collector"
ts=2020-02-24T17:25:43Z lvl=info msg="Start producer" service=collector
brokers=kafka.dev:9102
ts=2020-02-24T17:25:44Z lvl=info msg="Starting HTTP service"
ts=2020-02-24T17:25:44Z lvl=info msg="Starting server on" addr=0.0.0.0:13425
However I can't launch 0.0.0.0:13425 on my Mac , it shows me "This site can’t be reached0.0.0.0 refused to connect". It looks like my local machine doesn't look the docker . I know that Mac has some peculiarities but I pointed -p ( as I thought it should enough). Thanks a lot beforehand
The docker run -P (capital “P”) option asks Docker to pick a host port. That will almost always be a different port number from the one inside the container. You can print out the port number by using docker ps to find the container ID, and then docker port 0123456789ab to print out the actual port mapping. Once you’ve found the port number, you can use the special hostname localhost or the matching special IP address 127.0.0.1 and that port number to reach your container (not 0.0.0.0, a special address that means “everywhere”).
In typical use you’ll explicitly specify both host and container ports with a -p (little “p”) option, and also specify a --name so that you can find the container later.
docker run \
-it \
-p 13425:13425 \
--name clickstream_collector \
clickstream-collector_csapi \
...

Retrieving Container IP address after `lxc start`

I have the following script I'm running in cloud-init on my cloud provider. It grabs a container from another host on my network, starts it, and then attempts to forward a port on the host to the container:
lxc init ...
lxc remote add gateway 10.132.98.1:8099 --accept-certificate --password securpwd
lxc copy gateway:build-slave build-slave
lxc start build-slave
CONTAINER_IP=$(lxc list "build-slave" -c 4 | awk '!/IPV4/{ if ( $2 != "" ) print $2}')
iptables -t nat -A PREROUTING -i ens3 -p tcp --dport 2200 -j DNAT --to ${CONTAINER_IP}
The only problem is that there is an arbitrary delay between when lxc start returns and when the IPV4 info is available. My current solution is to add sleep 5s after the lxc start command, but I'm worried that if my server is under load, it might actually be longer than 5 seconds before the container is initialized.
Is there a better solution that doesn't rely on an arbitrary wait period?
As Lawrence pointed out in the comments, LXD provides a "proxy" device that can be set on the container. In this way, I don't have to know the container's IP address in order to setup the correct IPTABLES entry. LXD will instead setup my proxy rule for me when the container I specify starts.
I configured this like so:
DROPLET_PUB_IP=$(ip -f inet addr show ens3 | sed -En -e 's/.*inet ([0-9.]+).*/\1/p')
lxc config device add build-slave ssh-slave proxy listen=tcp:${DROPLET_PUB_IP}:2200 connect=tcp:localhost:22

How to reach docker container `localhost` from Mac?

Note this is different from How to expose a service running inside a docker container, bound to localhost, which can be addressed in multiple ways in Docker for Linux, say through --net host or even -v to bind my Linux-flavor client in etc. My problem is specific for Docker for Mac, so it's not as straightforward.
I have a TCP server binding to localhost:5005 running inside Docker for Mac. (For security reason, I must not bind to 0.0.0.0:5005.)
I have a TCP client sending request to this server from my Mac (not inside the docker container).
My question is, how do I make it work?
In Linux Docker, I would simply use --net=host so the server binds to my host lo interface, but it seems that Docker for Mac runs on a managed VM, so the host network behavior is different behavior.
To illustrate my point:
On MacBook
It simply would not work
[me#MacBook App]$ docker run -v `pwd`:/App -p 127.0.0.1:5005:5005 nitincypher/docker-ubuntu-python-pip /App/server.py
[me#MacBook App]$ ./client.py
Client received data:
On Linux
In comparison, it would be trivial to do on Linux by using host network mode. Since I'm using my Linux's lo interface as my container lo interface.
[me#Linux App]$ docker run -v `pwd`:/App --net=host nitincypher/docker-ubuntu-python-pip /App/server.py
Server Connection address: ('127.0.0.1', 52172)
Server received data: Hello, World!
[me#Linux App]$ ./client.py
Client received data: Hello, World!
My Simulated Server Code
Requirement: It MUST bind to localhost, and nothing else. So I cannot change it to 0.0.0.0.
#!/usr/bin/env python
import socket
TCP_IP = 'localhost'
TCP_PORT = 5005
BUFFER_SIZE = 20 # Normally 1024, but we want fast response
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
s.listen(1)
conn, addr = s.accept()
print 'Server Connection address:', addr
while 1:
data = conn.recv(BUFFER_SIZE)
if not data: break
print "Server received data:", data
conn.send(data) # echo
conn.close()
My Simulated Client Code
Requirement: It MUST be ran on MacBook, since the real client is written in CPP and compiled to run only on MacBook.
#!/usr/bin/env python
import socket
TCP_IP = 'localhost'
TCP_PORT = 5005
BUFFER_SIZE = 1024
MESSAGE = "Hello, World!"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(MESSAGE)
data = s.recv(BUFFER_SIZE)
s.close()
print "Client received data:", data
Here's a working solution. The basic idea is to use SSH tunneling to do the port forwarding.
High Level Idea
You first need to build a docker image to support SSH access, because
ubuntu image doesn't have a sshd out of box, and also
you will need to know the password of root of your running container.
Then you will spin up your container as what you would normally do except that you are doing that based on the new image you created.
You create a SSH tunneling session from your MacBook, then you run your client on MacBook as you would normally do.
For reference, the command for SSH tunneling can be found here, the process of creating a sshd docker image is explained here, and how to ssh into docker container is explained here
Steps
Create a Docker file Dockerfile
#Use whatever image you are using on Docker Linux , say "FROM ubuntu:16.04"
FROM nitincypher/docker-ubuntu-python-pip
RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:screencast' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# SSH login fix. Otherwise user is kicked off after login
RUN sed 's#session\s*required\s*pam_loginuid.so#session optional pam_loginuid.so#g' -i /etc/pam.d/sshd
ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
Create a Docker Image from the Dockerfile
[me#MacBook App]$ docker build -t my_ssh_python .
Spin up your server container
[me#MacBook App]$ docker run -d -P -v `pwd`:/App --name myserver my_ssh_python
Start your server inside the container
[me#MacBook App]$ docker exec myserver /App/server.py
Create a SSH tunnel
[me#MacBook App]$ ssh root#`hostname` -p `docker port myserver 22 | awk -F ":" '{print $2}'` -L 8000:localhost:8000 -N
#Password is "screencast" as you built in Dockerfile
Note that
a. You have to use the IP address of your MacBook instead of your docker container's IP address.
b. You will use the port where the default container ssh port 22 is mapped to on host
c. In tunneling -L 8000:localhost:8000, you are saying forward anything from your MacBook 8000 (the first 8000) to Docker container's localhost at port 8000
Now you can use you client locally
[me#MacBook App]$ ./client.py
Client received data: Hello, World!
And on server side, you can see
Server Connection address: ('127.0.0.1', 55396)
Server received data: Hello, World!

Change ssh tunnel direction with the same port?

I'm using an ssh tunnel to forward a port to a db server.
Let's say I'm using mysql, so my ssh command would be something along the lines of
ssh -fqTN -L 12345:127.0.0.1:3306 user#server.com
based on the method of transfer (sync from or sync to) I want to use either the -L or -R flags.
I do need the -L flag at first though, so I open the tunnel above anyway.
My question is though -
If after now run
ssh -fqTN -R 12345:127.0.0.1:3306 user#server.com
Will it replace the above command and make a reverse tunnel on the same port?
The second command will not "replace" the first command, but it will work just fine.
You started with:
ssh -fqTN -L 12345:127.0.0.1:3306 user#server.com
This opens port 12345 on your local system and forwards it to 127.0.0.1:3306 from the perspective of the remote system, so that you can access the mysql server on the remote system using local port 12345.
The second command...
ssh -fqTN -R 12345:127.0.0.1:3306 user#server.com
...opens port 12345 on the remote system and forwards it to 127.0.0.1:3306 from the perspective of your local system, allowing the remote system to access a mysql server on your local host via port 12345.
This doesn't conflict with the original command, so these can both be run at the same time.
Update
Responding to your comment here, because I want to quote some command output:
If I run:
ssh -R 12345:127.0.0.1:3306 remote_system
Then on remote_system I run lsof -i -n, I see:
sshd 23280 lars 10u IPv6 37263762 0t0 TCP [::1]:italk (LISTEN)
sshd 23280 lars 11u IPv4 37263763 0t0 TCP 127.0.0.1:italk (LISTEN)
And from /etc/services, we see that italk is port 12345. If you add -P to your lsof command line it will not try to translate port numbers to service names:
# lsof -i -n -P | grep 12345
sshd 23280 lars 10u IPv6 37263762 0t0 TCP [::1]:12345 (LISTEN)
sshd 23280 lars 11u IPv4 37263763 0t0 TCP 127.0.0.1:12345 (LISTEN)

How to connect to Docker API from another machine?

I'm trying to use the Docker API to connect to docker daemon from another machine. I am able to do this command successfully:
docker -H=tcp://127.0.0.1:4243 images
But NOT when I use the real IP address:
docker -H=tcp://192.168.2.123:4243 images
2013/08/04 01:35:53 dial tcp 192.168.2.123:4243: connection refused
Why can't I connect when using a non-local IP?
I'm using a Vagrant VM with the following in Vagrantfile: config.vm.network :private_network, ip: "192.168.2.123"
The following is iptables:
# Generated by iptables-save v1.4.12 on Sun Aug 4 01:24:46 2013
*filter
:INPUT ACCEPT [1974:252013]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1511:932565]
-A INPUT -p tcp -m tcp --dport 4243 -j ACCEPT
COMMIT
# Completed on Sun Aug 4 01:24:46 2013
# Generated by iptables-save v1.4.12 on Sun Aug 4 01:24:46 2013
*nat
:PREROUTING ACCEPT [118:8562]
:INPUT ACCEPT [91:6204]
:OUTPUT ACCEPT [102:7211]
:POSTROUTING ACCEPT [102:7211]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.16.42.0/24 ! -d 172.16.42.0/24 -j MASQUERADE
Came across a similar issue, one thing I don't see mentioned here is you need to start docker to listen to both the network and a unix socket. All regular docker (command-line) commands on the host assume the socket.
sudo docker -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock -d &
will start docker listening to any ip address on your host, as well as the typical unix socket.
You need to listen to 0.0.0.0. When you listen on 127.0.0.1, it means that no one outside your host will be able to connect.
Please note that in doing this, you have given anyone, and any URL sent to you by email access to your Docker API, and thus root permission.
you should, at minimum, secure your socket using https: http://docs.docker.com/articles/https/
There are 2 ways in configuring the docker daemon port
1) Configuring at /etc/default/docker file:
DOCKER_OPTS="-H tcp://127.0.0.1:5000 -H unix:///var/run/docker.sock"
2) Configuring at /etc/docker/daemon.json:
{
"hosts": ["tcp://<IP-ADDRESS>:<PORT>", "unix:///var/run/docker.sock"]
}
IP-ADDRESS - any address which is accessible can be used.
Restart the docker service after configuring the port.
The reason for adding both the user port[ tcp://127.0.0.1:5000] and default docker socket[unix:///var/run/docker.sock] is that the user port enables the access to the docker APIs whereas the default socket enables the CLI.

Resources