torservers / onionize-docker

Tor v3 onion services (hidden services) for Docker containers
https://hub.docker.com/r/torservers/onionize/
GNU General Public License v3.0
76 stars 15 forks source link

don't pick IP of first Network inside docker-gen template #3

Closed langfingaz closed 4 years ago

langfingaz commented 4 years ago

First: Thanks for this great project!

Summary: If the container providing a web service (e.g. service1) is connected to multiple docker networks (and has thus multiple IP addresses - one for each network), then the current torrc.tmpl will "randomly" choose one of the service1 IP addresses. This way it can happen, that onionize can't reach service1 on the chosen IP address as this IP address is from a network that onionize is not connected to.

Example

The web service 'service1' is available on the clearnet but to further respect the privacy of any visitors, they can also access it as an onion service.

version: '3'

services:
  onionize:
    container_name: onionize
    build: .
    restart: always
    volumes:
          - /var/run/docker.sock:/tmp/docker.sock:ro
    networks:
      - tor

  service1:
    image: ...
    expose:
      - 80
    environment:
      ONIONSERVICE_NAME: "service1"
    networks:
      - tor
      - clearnet_proxy

  proxy:
    image: nginx
    ports:
      - 80
      - 443
    environment:
    networks:
      - clearnet_proxy

onionize can only reach service1 via the tor network both containers are connected to.

If one restarts service1, the torrc file gets regenerated from the template. And the line HiddenServicePort 80 <IP>:80 inside torrc will sometimes have an IP starting with 172 (clearnet_proxy) or starting with 192 (tor).

If the first is the case, one can not reach the onion service. Only in the second case everything works as expected.

Possible Solution

One could use the container name variable (of service1) in the template file instead of choosing the IP address of the first network ({{ $network := index $value.Networks 0 }}, HiddenServicePort {{ $address.Port }} {{ $network.IP }}:{{ $address.Port }}) to communicate with it.

This would e.g. result in the following line inside torrc:

HiddenServicePort 80 service1:80

I tested this for my example (disabled docker-gen) and manually created the torrc file and it worked fine.

Alternative Solution

Another approach would be to iterate over the Networks array of RuntimeContainer and for each network check if the Network.Name matches any of the networks that onionize is connected to. If there is a match, take the IP address from that network.

moba commented 4 years ago

Thanks for outlining the problem and possible solutions in such a comprehensive way! It sounds like using the container name is indeed the cleaner way to approach this.

Pull requests welcome, otherwise I will see when I can find the time to address this myself.

moba commented 4 years ago

I played around with it a bit, and thought about it for a while, and I'm sufficiently confident now that this will work -- pushing a new release :) Thanks!