Linux network troubleshooting a la Dr. House


The following story is inspired by a recent case I had to troubleshoot at work. I think it is a nice example of troubleshooting Linux networking issues, so I’ve modified/simplified the setup a bit to be able to reproduce it on a VM. I’ll go through the troubleshooting steps in almost the same way we handled the actual case. Service names, IPs, ports, etc are all different that the real case as the focus should not be the example itself but the process.

It all started a few days ago when I was asked to help on an “unusual” case. Docker containers on every single host of an installation could not establish connections towards services that listen on the “main” IP of the host they run on, nor can they ping that IP, but the containers have full access to the internet and can connect to the service ports on other hosts in the LAN. As everyone who has done even a tiny bit of support, asking whether something changed recently in the setup is always replied back with a single global truth: “nothing has recently changed, it just stopped working”.
Challenge accepted!

Reproduction setup

For reproduction purposes I’ve used a VM with one ethernet interface, and a docker bridge. In this VM I have injected the same problem as with the real case. Even though the real case case was a bit more complicated, to make following the post somewhat easier, I’ve used only one service listening on the host, an Elasticsearch process, and only one Kibana docker container that needs to communicate with Elasticsearch on the host.

Troubleshooting process

Host interfaces:

2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc mq state UP group default qlen 1000
    link/ether 06:ce:3b:94:fe:ac brd ff:ff:ff:ff:ff:ff
    inet brd scope global dynamic ens5
       valid_lft 3572sec preferred_lft 3572sec
    inet6 fe80::4ce:3bff:fe94:feac/64 scope link 
       valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:e9:38:3d:a8 brd ff:ff:ff:ff:ff:ff
    inet scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:e9ff:fe38:3da8/64 scope link 
       valid_lft forever preferred_lft forever

Kibana’s config has the following ENV variable set ELASTICSEARCH_HOSTS=, and for simplification purposes let’s assume that this IP could not be changed.

As originally described, curl from the container towards the service IP:port does not work

(container) bash-4.2$ curl -v
* About to connect() to port 9200 (#0)
*   Trying

it just hangs there without error. There’s no DNS resolution involved here, straight curl towards the IP:port

Let’s check if the service is actually listening on the host

[root@ip-172-31-45-100 ~]# ss -ltnp | grep 9200
LISTEN      0      128                             [::]:9200                                  [::]:*                   users:(("java",pid=17892,fd=257))

The service listens on 9200. Since the service listens on all interfaces, let’s curl from the container towards the service IP:port on the docker0 interface.

bash-4.2$ curl -v
* About to connect() to port 9200 (#0)
*   Trying
* Connected to ( port 9200 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host:
> Accept: */*
< HTTP/1.1 200 OK
< content-type: application/json; charset=UTF-8
< content-length: 524
  "name" : "node1",
  "cluster_name" : "centos7",
  "cluster_uuid" : "d6fBSua6Q9OvSu534roTpA",
  "version" : {
    "number" : "7.7.0",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
    "build_date" : "2020-05-12T02:01:37.602180Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  "tagline" : "You Know, for Search"

that works, so the service is running properly. Curl-ing the service from the host using the host’s IP also works

[root@ip-172-31-45-100 ~]# curl
  "name" : "node1",
  "cluster_name" : "centos7",
  "cluster_uuid" : "d6fBSua6Q9OvSu534roTpA",
  "version" : {
    "number" : "7.7.0",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
    "build_date" : "2020-05-12T02:01:37.602180Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  "tagline" : "You Know, for Search"

Let’s check for internet connectivity from the container

bash-4.2$ curl -v
* About to connect() to port 80 (#0)
*   Trying
* Connected to ( port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host:
> Accept: */*
< HTTP/1.1 301 Moved Permanently
< Date: Sun, 31 May 2020 10:10:27 GMT
< Content-Type: text/html
< Transfer-Encoding: chunked
< Connection: keep-alive
< Location:
< Served-In-Seconds: 0.000
< CF-Cache-Status: HIT
< Age: 5334
< Expires: Sun, 31 May 2020 14:10:27 GMT
< Cache-Control: public, max-age=14400
< cf-request-id: 030bcf27a3000018e57f0f5200000001
< Server: cloudflare
< CF-RAY: 59bfe7b90b7518e5-FRA
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>

internet connectivity for the container works just fine. Let’s curl to another host in the same LAN on the same service port.

bash-4.2$ curl -v
* About to connect() to port 9200 (#0)
*   Trying
* Connected to ( port 9200 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host:
> Accept: */*
< HTTP/1.1 200 OK
< content-type: application/json; charset=UTF-8
< content-length: 524
  "name" : "node2",
  "cluster_name" : "centos7",
  "cluster_uuid" : "d6fBSua6Q9OvSu534roTpA",
  "version" : {
    "number" : "7.7.0",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
    "build_date" : "2020-05-12T02:01:37.602180Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  "tagline" : "You Know, for Search"

That also works. Time to use the swiss army knife of network troubleshooting, tcpdump. If you want to find which veth interface a container uses you can either use dockerveth or use the following commands to figure it out manually.
Get the iflink of container’s eth0:

[root@ip-172-31-45-100 ~]# docker exec -it <container-name> bash -c 'cat /sys/class/net/eth0/iflink'

In this case that would be:

# docker exec -it kibana bash -c 'cat /sys/class/net/eth0/iflink'

then find the file name of the ifindex that contains that link number in `/sys/class/net/veth*/ifindex` of the host

[root@ip-172-31-45-100 ~]# grep -lw 41 /sys/class/net/veth*/ifindex

`veth0006ca6` is what we need to use. Let’s run tcpdump on it

[root@ip-172-31-45-100 ~]# tcpdump -nni veth0006ca6
10:06:16.745143 IP > Flags [S], seq 1062649548, win 29200, options [mss 1460,sackOK,TS val 1781316 ecr 0,nop,wscale 7], length 0
10:06:16.749126 IP > Flags [S], seq 4174345004, win 29200, options [mss 1460,sackOK,TS val 1781320 ecr 0,nop,wscale 7], length 0
10:06:16.749131 IP > Flags [S], seq 1386880792, win 29200, options [mss 1460,sackOK,TS val 1781320 ecr 0,nop,wscale 7], length 0

the syn packet is seen going out of the container’s veth interface. So let’s tcpdump on docker0

[root@ip-172-31-45-100 ~]# tcpdump -nni docker0
10:07:07.813153 IP > Flags [S], seq 4114480937, win 29200, options [mss 1460,sackOK,TS val 1396384 ecr 0,nop,wscale 7], length 0
10:07:07.845141 IP > Flags [S], seq 3273546229, win 29200, options [mss 1460,sackOK,TS val 1412416 ecr 0,nop,wscale 7], length 0
10:07:07.845147 IP > Flags [S], seq 2062214864, win 29200, options [mss 1460,sackOK,TS val 1412416 ecr 0,nop,wscale 7], length 0

the syn packet can also be seen on the docker0 bridge. The syn packet cannot be seen on the interface (ens5) that has the service IP ( on it, since it doesn’t traverse that link to go outside the host.

[root@ip-172-31-45-100 ~]# tcpdump -nni ens5 port 9200 or icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), capture size 262144 bytes

Let’s check routing entries.

[root@ip-172-31-45-100 ~]# ip route ls
default via dev ens5 dev docker0 proto kernel scope link src dev ens5 proto kernel scope link src 

Nothing interesting here at all. Time to check iptables.

[root@ip-172-31-45-100 ~]# iptables -nxvL
Chain INPUT (policy ACCEPT 169 packets, 27524 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy DROP 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
     368    27870 DOCKER-ISOLATION  all  --  *      *             
     184    14254 DOCKER     all  --  *      docker0             
     184    14254 ACCEPT     all  --  *      docker0              ctstate RELATED,ESTABLISHED
     184    13616 ACCEPT     all  --  docker0 !docker0             
       0        0 ACCEPT     all  --  docker0 docker0             

Chain OUTPUT (policy ACCEPT 109 packets, 10788 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain DOCKER (1 references)
    pkts      bytes target     prot opt in     out     source               destination         

Chain DOCKER-ISOLATION (1 references)
    pkts      bytes target     prot opt in     out     source               destination         
     368    27870 RETURN     all  --  *      *        

[root@ip-172-31-45-100 ~]# iptables -nxvL -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
     204    12200 DOCKER     all  --  *      *              ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 6 packets, 456 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 DOCKER     all  --  *      *           !          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT 6 packets, 456 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
      92     6808 MASQUERADE  all  --  *      !docker0           

Chain DOCKER (2 references)
    pkts      bytes target     prot opt in     out     source               destination         
     191    11460 RETURN     all  --  docker0 *    

[root@ip-172-31-45-100 ~]# iptables -nxvL -t mangle
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination         

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
    pkts      bytes target     prot opt in     out     source               destination  

There’s not even a DROP rule at all and all the policies are set to ACCEPT. iptables is definitely not dropping the connection. Even if there was a DROP rule, we would see the packet on tcpdump…so where’s the packet going ?

Let’s add an extra rule for both FORWARD and INPUT chains just to see if iptables can match these rules as the packets are passing by.

[root@ip-172-31-45-100 ~]# iptables -I INPUT -p tcp --dport 9200
[root@ip-172-31-45-100 ~]# iptables -I FORWARD -p tcp --dport 9200

wait for a while and then check the statistics of those 2 rules:

[root@ip-172-31-45-100 ~]# iptables -nxvL | grep 9200
       0        0            tcp  --  *      *              tcp dpt:9200
       0        0            tcp  --  *      *              tcp dpt:9200

no packets match these 2 rules at all! Time to inspect the container and the docker bridge network.

[root@ip-172-31-45-100 ~]# docker network inspect bridge
        "Name": "bridge",
        "Id": "a6290df54ea24d14faa8d003d17802b3f8a4967680bc0c82c1211ab75d1815e2",
        "Created": "2020-05-31T09:40:19.81958733Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                    "Subnet": ""
        "Internal": false,
        "Attachable": false,
        "Containers": {},
        "Options": {
            "": "true",
            "": "true",
            "": "true",
            "": "",
            "": "docker0",
            "": "1500"
        "Labels": {}

pretty standard options for the bridge network, even `enable_icc` is set to `true`. What about the container though ?

[root@ip-172-31-45-100 ~]# docker inspect kibana
        "Id": "2f08cc190b760361d9aa2951b4c9c407561fe35b8dbdc003f3f535719456f460",
        "Created": "2020-05-31T10:24:11.942315341Z",
        "Path": "/usr/local/bin/dumb-init",
        "Args": [
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 3735,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-05-31T10:24:12.329214827Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        "Image": "sha256:eadc7b3d59dd47b1b56f280732f38d16a4b31947cbc758516adbe1df5472b407",
        "ResolvConfPath": "/var/lib/docker/containers/2f08cc190b760361d9aa2951b4c9c407561fe35b8dbdc003f3f535719456f460/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/2f08cc190b760361d9aa2951b4c9c407561fe35b8dbdc003f3f535719456f460/hostname",
        "HostsPath": "/var/lib/docker/containers/2f08cc190b760361d9aa2951b4c9c407561fe35b8dbdc003f3f535719456f460/hosts",
        "LogPath": "",
        "Name": "/kibana",
        "RestartCount": 0,
        "Driver": "overlay2",
        "MountLabel": "system_u:object_r:svirt_sandbox_file_t:s0:c434,c792",
        "ProcessLabel": "system_u:system_r:svirt_lxc_net_t:s0:c434,c792",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "journald",
                "Config": {}
            "NetworkMode": "bridge",
            "PortBindings": {
                "5601/tcp": [
                        "HostIp": "",
                        "HostPort": "5601"
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            "AutoRemove": true,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "CapAdd": null,
            "CapDrop": null,
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "docker-runc",
            "ConsoleSize": [
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": null,
            "BlkioDeviceReadBps": null,
            "BlkioDeviceWriteBps": null,
            "BlkioDeviceReadIOps": null,
            "BlkioDeviceWriteIOps": null,
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DiskQuota": 0,
            "KernelMemory": 0,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": -1,
            "OomKillDisable": false,
            "PidsLimit": 0,
            "Ulimits": null,
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0
        "GraphDriver": {
            "Name": "overlay2",
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/84217deb518fa6b50fb38aab03aa6a819150e0a248cf233bda8091b136c4825a-init/diff:/var/lib/docker/overlay2/bfda0aa2ec51f7047b5694e5daf89735f3021691e6154bc370827c168c4572f0/diff:/var/lib/docker/overlay2/5d32d74a3bb95b8e3377b1c115622f12a817a591936c4ae2da4512bc2e281e4b/diff:/var/lib/docker/overlay2/6482e711a89a90bebd61834aa8bd3463f567684dd3cdbbf2698179b752fdad7b/diff:/var/lib/docker/overlay2/4ae81e6a07956c974d985674c35e113ad3fbd9f4fdde43f4752c0e36a1153e69/diff:/var/lib/docker/overlay2/8330cdd839ec316133d659805f2839d1e65b16fbf7035324f419c2aa8d097925/diff:/var/lib/docker/overlay2/cd377c8c6fb23d050771d55ca15253cc9fa5043c7e49f41a2f73acd25f8e7ca9/diff:/var/lib/docker/overlay2/408c72d7e496be76503bbb01d5248c25be98e2290d71cae83d8d5d09d714f81d/diff:/var/lib/docker/overlay2/20068d51c4dd214db7b2b9d30fe13feb2e8ab35de646c9b652fea255476d396b/diff:/var/lib/docker/overlay2/0fdedfd6dbb551d32a9e826188a74936d0cec56e97c1b917fdd04b0e49a59a70/diff:/var/lib/docker/overlay2/0238ff31fbd60fdeaee1e162c92a1aa46735ec7b17df3b11455c09f18657c30f/diff:/var/lib/docker/overlay2/99a7a64a569e5e524e4139f9cf95bd929744c85c1633bcd8173c9172756c3233/diff",
                "MergedDir": "/var/lib/docker/overlay2/84217deb518fa6b50fb38aab03aa6a819150e0a248cf233bda8091b136c4825a/merged",
                "UpperDir": "/var/lib/docker/overlay2/84217deb518fa6b50fb38aab03aa6a819150e0a248cf233bda8091b136c4825a/diff",
                "WorkDir": "/var/lib/docker/overlay2/84217deb518fa6b50fb38aab03aa6a819150e0a248cf233bda8091b136c4825a/work"
        "Mounts": [],
        "Config": {
            "Hostname": "2f08cc190b76",
            "Domainname": "",
            "User": "kibana",
            "AttachStdin": false,
            "AttachStdout": true,
            "AttachStderr": true,
            "ExposedPorts": {
                "5601/tcp": {}
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
            "Cmd": [
            "Image": "",
            "Volumes": null,
            "WorkingDir": "/usr/share/kibana",
            "Entrypoint": [
            "OnBuild": null,
            "Labels": {
                "license": "Elastic License",
                "": "2020-05-12T03:25:49.654Z",
                "org.label-schema.license": "Elastic License",
                "": "kibana",
                "org.label-schema.schema-version": "1.0",
                "org.label-schema.url": "",
                "org.label-schema.usage": "",
                "org.label-schema.vcs-url": "",
                "org.label-schema.vendor": "Elastic",
                "org.label-schema.version": "7.7.0",
                "org.opencontainers.image.created": "2020-05-04 00:00:00+01:00",
                "org.opencontainers.image.licenses": "GPL-2.0-only",
                "org.opencontainers.image.title": "CentOS Base Image",
                "org.opencontainers.image.vendor": "CentOS"
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "258a4a11f55f7425b837c7d5c0420dd344add081be79da7e33c146501dd8f0ec",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "5601/tcp": [
                        "HostIp": "",
                        "HostPort": "5601"
            "SandboxKey": "/var/run/docker/netns/258a4a11f55f",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "7126885dddf9ff031f2ff8c3b2cbd14708391dae619020bdb40efe7a849a01c7",
            "Gateway": "",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "a6290df54ea24d14faa8d003d17802b3f8a4967680bc0c82c1211ab75d1815e2",
                    "EndpointID": "7126885dddf9ff031f2ff8c3b2cbd14708391dae619020bdb40efe7a849a01c7",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02"

all looks very normal regarding the docker container. Let’s check sysctl settings in /etc

[root@ip-172-31-45-100 ~]# ls -Fla /etc/sysctl.d/
total 12
drwxr-xr-x.  2 root root   28 May 31 09:34 ./
drwxr-xr-x. 84 root root 8192 May 31 10:15 ../
lrwxrwxrwx.  1 root root   14 May 31 09:34 99-sysctl.conf -> ../sysctl.conf

[root@ip-172-31-45-100 ~]# cat /etc/sysctl.d/99-sysctl.conf 

# sysctl settings are defined through files in
# /usr/lib/sysctl.d/, /run/sysctl.d/, and /etc/sysctl.d/.
# Vendors settings live in /usr/lib/sysctl.d/.
# To override a whole file, create a new file with the same in
# /etc/sysctl.d/ and put new settings there. To override
# only specific settings, add a file with a lexically later
# name in /etc/sysctl.d/ and put new settings there.
# For more information, see sysctl.conf(5) and sysctl.d(5).

nothing interesting here as well. What if someone has messed up ip forwarding via other means though ?

[root@ip-172-31-45-100 ~]# sysctl -a 2>/dev/null| grep forward | grep -v ipv6
net.ipv4.conf.all.forwarding = 1
net.ipv4.conf.all.mc_forwarding = 0
net.ipv4.conf.default.forwarding = 1
net.ipv4.conf.default.mc_forwarding = 0
net.ipv4.conf.docker0.forwarding = 1
net.ipv4.conf.docker0.mc_forwarding = 0
net.ipv4.conf.ens5.forwarding = 1
net.ipv4.conf.ens5.mc_forwarding = 0
net.ipv4.conf.lo.forwarding = 1
net.ipv4.conf.lo.mc_forwarding = 0
net.ipv4.ip_forward = 1
net.ipv4.ip_forward_use_pmtu = 0

all looks fine here too. Let’s check some more sysctl settings regarding bridge + iptables

[root@ip-172-31-45-100 ~]# sysctl -a 2>/dev/null| grep bridge
net.bridge.bridge-nf-call-arptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-filter-pppoe-tagged = 0
net.bridge.bridge-nf-filter-vlan-tagged = 0
net.bridge.bridge-nf-pass-vlan-input-dev = 0

everything still looks fine in these configuration settings, but the packets from the container still can’t reach the host.
Next step is to setup a netcat listening service on the host on a different port and try to connect to it via the container. That still doesn’t work, no packets to be seen on ens5.
Could it be ebtables ? way..but what if…

[root@ip-172-31-45-100 ~]# ebtables -L
Bridge table: filter
Bridge chain: INPUT, entries: 0, policy: ACCEPT
Bridge chain: FORWARD, entries: 0, policy: ACCEPT
Bridge chain: OUTPUT, entries: 0, policy: ACCEPT

still nothing interesting. Could it be a kernel bug ? is this some custom kernel ?

[root@ip-172-31-45-100 ~]# uname -a
Linux 3.10.0-1062.12.1.el7.x86_64 #1 SMP Tue Feb 4 23:02:59 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

nope…that’s a vanilla centos7 kernel. Could it be nftables ? On 3.10 kernel and centos7 ?

[root@ip-172-31-45-100 ~]# nft list tables
-bash: nft: command not found

Nobody uses nftables yet, right ? Another wild thought, are there any ip rules defined ?

[root@ip-172-31-45-100 ~]# ip rule ls
0:    from all lookup local 
100:    from lookup 1 
32766:    from all lookup main 
32767:    from all lookup default 

bingo, there’s a rule with priority 100 that matches the host’s IP address! What is this ip rule doing there ? Let’s check routing table 1 that the lookup of rule 100 points to

[root@ip-172-31-45-100 ~]# ip route ls table 1
default via dev ens5 dev ens5 scope link 

at last, here’s the answer!

There’s an IP rule entry that says that packets with a source IP of the ens5 interface should lookup routing entries only in routing table 1, which is not the main routing table. That routing table knows nothing about the docker network ( Let’s delete the rule from the host

[root@ip-172-31-45-100 ~]# ip rule del from tab 1 priority 100

and check if the container can contact the service now

(container) bash-4.2$ curl
  "name" : "node1",
  "cluster_name" : "centos7",
  "cluster_uuid" : "d6fBSua6Q9OvSu534roTpA",
  "version" : {
    "number" : "7.7.0",
    "build_flavor" : "default",
    "build_type" : "rpm",
    "build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
    "build_date" : "2020-05-12T02:01:37.602180Z",
    "build_snapshot" : false,
    "lucene_version" : "8.5.1",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  "tagline" : "You Know, for Search"


Where’s the SYN+ACK ?

Does the SYN packet reach the listening service ? No…and the reason is rp_filter. Centos7 sets net.ipv4.conf.default.rp_filter=1, so when docker0 interface gets created it is set to net.ipv4.conf.docker0.rp_filter=1.

Here’s what rp_filter values mean according to kernel documentation:

  • 0 – No source validation.
  • 1 – Strict mode as defined in RFC3704 Strict Reverse Path Each incoming packet is tested against the FIB and if the interface is not the best reverse path the packet check will fail. By default failed packets are discarded.
  • 2 – Loose mode as defined in RFC3704 Loose Reverse Path Each incoming packet’s source address is also tested against the FIB and if the source address is not reachable via any interface the packet check will fail.

After reverting the deleted ip rule via ip rule add from tab 1 priority 100 and setting sysctl -w net.ipv4.conf.docker0.rp_filter=0 we can see the SYN+ACK packet going out of ens5 interface towards the default gateway.

[root@ip-172-31-45-100 ~]# tcpdump -enni ens5 port 9200
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on ens5, link-type EN10MB (Ethernet), capture size 262144 bytes
15:44:19.028353 06:ce:3b:94:fe:ac > 06:1b:e5:19:30:12, ethertype IPv4 (0x0800), length 74: > Flags [S.], seq 1431574088, ack 1879007024, win 26847, options [mss 8961,sackOK,TS val 22063599 ecr 22063599,nop,wscale 7], length 0
15:44:20.029163 06:ce:3b:94:fe:ac > 06:1b:e5:19:30:12, ethertype IPv4 (0x0800), length 74: > Flags [S.], seq 1431574088, ack 1879007024, win 26847, options [mss 8961,sackOK,TS val 22064600 ecr 22063599,nop,wscale 7], length 0
15:44:21.229126 06:ce:3b:94:fe:ac > 06:1b:e5:19:30:12, ethertype IPv4 (0x0800), length 74: > Flags [S.], seq 1431574088, ack 1879007024, win 26847, options [mss 8961,sackOK,TS val 22065800 ecr 22063599,nop,wscale 7], length 0

Finding such discarded packets, called martians, in the logs can be done by enabling log_martians via sysctl -w net.ipv4.conf.all.log_martians=1. Example syslog message:

May 31 16:01:08 ip-172-31-45-100 kernel: IPv4: martian source from, on dev docker018
May 31 16:01:08 ip-172-31-45-100 kernel: ll header: 00000000: 02 42 e9 38 3d a8 02 42 ac 11 00 02 08 00 .B.8=..B......

But why ?

Why was the rule there in the original case ? Multihoming was tried, it didn’t work as expected and not all the configs were removed. Grep-ing /etc for the host’s IP found the following file:

/etc/sysconfig/network-scripts/rule-ens5:from tab 1 priority 100

In multihoming it’s common that packets reaching a host on interface X should also be replied back from interface X. Part of a method to achieve this is to assign each interface its own routing table.

So when asked to troubleshoot networking issues act like Dr. House would, assume the worst.

P.S. thanks to Markos for the comments on improving the blogpost

Graphing Covid-19 related data for Greece using Elastic’s ElasticSearch Service



A few weeks ago I started converting the Covid-19 daily reports from Greek National Public Health Organization (EODY) to json documents, and publishing them to Github in a repository called covid19-gr-json. Reasoning behind this effort was that EODY does not publish their data in a reusable format, one that “machines” can easily read and parse. There are many websites that have created their own Covid-19 graphs but most of them have very basic stats (cases/day, deaths/day) and they state that their data sources are coming from media sources, without letting you access and re-use their original data. I haven’t been able to locate any other open data set regarding Covid-19 data for Greece that is not based on media sources but from official data coming out of EODY.

Report frequency and data consistency

After a few days of trying to convert these daily reports to json, EODY stopped publishing them. 3 days later EODY published another report with a different set of metrics than the previous reports. This new report did not have a per region analysis of cases and EODY also stopped publishing data for the number of hospitalized people or how many people have recovered. 4 more days passed without a report. Then EODY started publishing daily reports again, we’re now at 9 days in a row, but the metrics are again different than the previous ones published. There’s now a drill down by age and gender regarding cases, deaths and people in intensive care (IC). Still no mention of how many people have recovered though or how many are hospitalized but are not in IC. The result is that json files in the repository cannot be consistent since the original sources are not consistent. Such is life.

Visualizing data

A few days had passed since I started converting pdf reports to json and I wanted to see how easy it is to visualize some of it. Since data were in json format, the easiest thing for me to do was to store them to an Elasticsearch cluster and create visualizations using Kibana. Working at Elastic has its perks, I created a new Elastic stack deployment in ElasticSearch Service (ESS), and posted the json documents to it. I had to make a tough decision though, which graph tool from Kibana to use to visualize data. I started using line graphs but soon switched to Time Series Visual Builder (TSVB) as it’s easier to use and allows to visualize multiple metrics/time series in the same graph. I believe it’s producing way more beautiful visualizations anyway. After creating some visualizations I also created a dashboard, took some screenshots and shared them with friends.

Allowing access to dashboards

As people took notice of the json files in the repo they started pinging me to create some visualizations from them. I created a Kibana readonly user and shared the password with a few of them. That worked well for a couple of days, but sharing a password for a readonly view is a bit meeeh. I wondered if I could create a password-less version of it and post the URL publicly. Publishing a URL in the form of is not exactly memorable either. I googled if it’s possible to post credentials to Kibana, and indeed it is. So nginx to the rescue!

Reverse proxy to ESS

I first tried to use a URL within, eg to point directly to Kibana hosted on ESS. Because of the various location rules already used in my nginx config this quickly became more complicated than it had to, so I created a new subdomain for it, Here’s the reverse proxy config:

    location / {
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection 'upgrade';
      proxy_set_header Host $proxy_host;
      proxy_cache_bypass $http_upgrade;
      proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
      proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header  X-Forwarded-Proto $scheme;
      auth_basic "Basic Auth";
      proxy_set_header Authorization "Basic bXl1c2VyOm15cGFzcw=="; # base64-encoded username:password to pass in header
      proxy_set_header x-forwarded-user $remote_user;
      proxy_hide_header kbn-license-sig;
      proxy_hide_header kbn-xpack-sig;
      proxy_hide_header kbn-name;
      proxy_hide_header x-found-handling-server;
      proxy_hide_header x-found-handling-instance;
      proxy_hide_header x-found-handling-cluster;
      proxy_hide_header x-cloud-request-id;

Authorization header

Authentication is based on the base64 encoded output of username:password combination which is to be posted to Kibana. Create it via:

$ echo -n myuser:mypass | base64

Adding these 2 config options is enough for nginx reverse proxy to authenticate to Kibana:

auth_basic "Basic Auth";
proxy_set_header Authorization "Basic bXl1c2VyOm15cGFzcw==";

Header removal

While not strictly necessary, I think it’s a good practice to remove non-essential headers being sent back to the browser via the reverse proxy.

End Result

One Let’s Encrypt certificate later and tada! is live!


Do you want to contribute either by converting EODY’s reports to json or by improving the above visualizations dashboards ? leave a comment, send an email or ping me via twitter.

Συντονισμένες έφοδοι της αστυνομίας στο μη κερδοσκοπικό οργανισμό Zwiebelfreunde σε διάφορες περιοχές της Γερμανίας

(Σημείωση: To παρακάτω κείμενο αποτελεί ελεύθερη μετάφραση του Το κείμενο έχει υποστεί μικρές αλλαγές καθώς έχει αλλάξει το πρόσωπο από το πρώτο πληθυντικό που ήταν αρχικά γραμμένο.)

Στις 20 Ιουνίου, η αστυνομία εισέβαλε σε πέντε τοποθεσίες, συντονισμένα στις 6:00 το πρωί: στις ιδιωτικές κατοικίες των τριών μελών του οργανισμού Zwiebelfreunde, Jens, Juris και Moritz, στην καταστατική έδρα του οργανισμού στην Δρέσδη (ένα δικηγορικό γραφείο), και στην κατοικία ενός πρώην μέλους του οργανισμού.

Μεταβείτε στο κάτω μέρος της σελίδας για συνδέσμους (links) σε διάφορα δημοσιεύματα του τύπου με εκτενείς αναφορές για το τι έγινε σε αυτές τις εφόδους.

(Η σύντομη περίληψη είναι ότι ) — Η ιστορία ξεκινάει με το αριστερό blog “Krawalltouristen” (“μπαχαλό”-τουρίστες) να καλεί σε δράσεις διαμαρτυρίας γύρω από το συνέδριο του δεξιού κόμματος AfD στο Augsburg της Γερμανίας. Οι διωκτικές αρχές (εισαγγελέας) υποστηρίζουν ότι αυτό περιλαμβάνει παροτρύνσεις για βία.

Η Γερμανική αστυνομία προκειμένου να βρει την συντακτική ομάδα του αναφερόμενου blog, αντί να ζητήσει πληροφορίες από τον πάροχο email που χρησιμοποιούσε το blog, το, έκρινε σκόπιμο να εισβάλει στο γερμανικό οργανισμό Zwiebelfreunde.

Το Zwiebelfreunde συνεργάζεται με το Riseup Labs, μια μη κερδοσκοπική οργάνωση με έδρα την Αμερική, και διαχειρίζεται τις δωρεές μέσω Ευρωπαϊκών ηλεκτρονικών εμβασμάτων για τη συλλογικότητα (κολεκτίβα) Riseup.
Τα χρήματα χρησιμοποιούνται σε συνεργασία με την κολεκτίβα για την κάλυψη των εξόδων ανάπτυξης λογισμικού, ταξιδιών, και της υποδομής διακομιστών Tor της Riseup.

Για περισσότερες λεπτομέρειες δείτε τις δημοσιεύσεις από άλλα μέσα.

Ποια δεδομένα επηρεάζονται και πως;

Μια λίστα από πράγματα που ο οργανισμός έχει ισχυρούς λόγους να πιστεύει ότι δεν επηρεάζονται , και μπορούν να θεωρηθούν ασφαλή:

* κάθε σχετική τεχνική υποδομή των Torservers: Tor relays, mail servers, web servers
* κάθε τεχνική υποδομή της Riseup (γιατί δεν έχουμε σχέση με αυτή)
* το ή άλλη τεχνική υποδομή του cryptoparty
* κλειδιά PGP, SSH κλειδιά, OTR κλειδιά, κ.λ.π

Η αστυνομία κατάσχεσε την πλειοψηφία του ηλεκτρονικού εξοπλισμού μέσων αποθήκευσης (σκληρούς δίσκους, laptops, ηλεκτρονικούς υπολογιστές GnuPG Smartcards/Yubikeys), αλλά είναι ασφαλές να θεωρήσουμε ότι δεν θα μπορέσουν να τα αποκρυπτογραφήσουν.
Επίσης κατάσχεσαν κινητά τηλέφωνα, τα οποία ακόμη και να κατάφερναν να αποκρυπτογραφήσουν, δεν περιέχουν κωδικούς πρόσβασης ή οτιδήποτε άλλο που μπορεί να επηρεάσει την τεχνική υποδομή ή τις επικοινωνίες που είναι αποθηκευμένες σε αυτά τα τηλέφωνα.

Παρόλα αυτά, έχει ανασταλεί το κοινό PGP κλειδί επικοινωνίας, και θα αντικατασταθούν όλο και περισσότερα κλειδιά και κωδικούς πρόσβασης με το πέρασμα του χρόνου. Το νέο κλειδί είναι το 0x74A312092938F2F0 και έχει υπογραφεί (signed) από το προηγούμενο κλειδί.

Οπότε, τί επηρεάζεται;

Πέρα από τα κρυπτογραφήμενα δεδομένα, η αστυνομία είχε το νομικό δικαίωμα να κατάσχει έγγραφα σχετικά με τον τραπεζικό λογαριασμό της Riseup αρχίζοντας από τον Ιανουάριο του 2018. Επίσης, παρέλαβαν αυτά τα έγγραφα και από την τράπεζα του οργανισμού, την GLS Gemeinschaftsbank.
Ο οργανισμός υποχρεούται να διατηρεί αρχεία και αποδείξεις από όλες τις δαπάνες για φορολογικούς λόγους. Αυτά τα έγγραφα φυλάσσονταν “ασφαλή” σε ένα πυρίμαχο χρηματοκιβώτιο.

Παρά τις διαμαρτυρίες, κατάσχεσαν όλα τα εκτυπωμένα έγγραφα σχετικά με τα πρότζεκτ του οργανισμού και των συνεργατών τους, από την αρχή της σύστασης του οργανισμού το 2011.

Αυτό περιλαμβάνει εξαιρετικά ευαίσθητα προσωπικά δεδομένα χορηγών, ταυτότητες από ακτιβίστριες/ές που δέχθηκαν επιστροφές δαπανών ή πληρωμές, και την λίστα των μελών του οργανισμού.

Αν έχετε δωρίσει στο Torservers ή Tails ή Riseup μέσω Ευρωπαικής τραπεζικής συναλλαγής, τα δεδομένα σας είναι πολύ πιθανόν στα χέρια της Γερμανικής αστυνομίας. (IBAN, αριθμός λογαριασμού, κάτοχος λογαριασμού, ποσό και ημερομηνία)

Έγινε ότι ήταν δυνατό για να αποφύγει ο οργανισμός μια τέτοια παραβίαση προσωπικών δεδομένων, και τώρα κάνει τα πάντα για να την πολεμήσει:

1. Οι δικηγόροι ζήτησαν επίμονα να επιστρέψουν πίσω τον εξοπλισμό του οργανισμού. Η πλειονότητα του εξοπλισμού δεν ανήκει στο Zwiebelfreunde, και μέρος του δεν είναι καν δικός τους. Το αρνήθηκαν. Έχουν προσφύγει στο δικαστήριο για αυτό.

2. Το ένταλμα κατάσχεσης αναφέρει συγκεκριμένα είδη. Αυτό δεν τηρήθηκε.

3. Ο οργανισμός υποστηρίζει ότι ακόμη και τα αρχικά εντάλματα κατάσχεσης ήταν σαφώς υπερβολικά, και αυτό χρησιμοποιήθηκε ως δικαιολογία για να αποκτήσουν πρόσβαση σε δεδομένα μελών και χορηγών.
Ο οργανισμός δεν έχει καμία σχέση με την υποδομή της Riseup. Κατά την διάρκεια των εφόδων, οι αστυνομικές δυνάμεις ξεκάθαρα έδωσαν την εντύπωση ότι γνώριζαν πως δεν είχαν καμία σχέση είτε με την Riseup ή με το “μπαχαλό-τουρίστες” blog. Κανένας από τον οργανισμό δεν είχε ακούσει για αυτό το blog πριν!

Ο οργανσιμός ευχαριστεί για την γρήγορη και μη γραφειοκρατική οικονομική στήριξη από την Renewable Freedom Foundation, τι λογιστική υποστήριξη του Chaos Computer Club, και όλες τις ευγενικές προσφορές βοήθειας από διάφορες κοινότητες.

Αν δεν φοβάσαι να δωρίσεις σε λογαριασμούς που πιθανότατα παρακολουθούνται μπορείς ακόμη να το κανείς στο


Tormap – World map of Tor nodes – 5 years later

5 years ago I forked Moritz’s tormap project, updated it a bit and wrote about it. Tormap kept running for years until some changes in googlemaps broke it, not all KMLs were loading as they should. I later on figured out that googlemaps didn’t like that some of the KML files were larger than 3Mb. I didn’t have much time to play with it until recently, so a few days ago I decided to make it work again. I used newer googlemaps v3 API calls and compressed KML (KMZ) files to make it work. Then @iainlearmonth and @nusenu_ suggested making even more changes…

Their first suggestion was to use onionoo instead of parsing consensus on my own and running geoip on it, onionoo already provides that in a nice json output. Their other suggestion was to switch tormap to use OpenStretMap instead of googlemaps mostly because googlemaps block some Tor exit nodes and the tiles didn’t appear on the map when visiting over Tor. Both of these issues are fixed now.

I used leaflet.js and a couple of plugins like leaflet-plugins (for KML parsing) and leaflet-color-markers for the switch to OpenStreetMap. I will admit that using googlemaps APIs was far more convenient for someone without any javascript knowledge like me.

Maybe in the next 5 years I will have time again to implement their other suggestion, creating maps of nodes based on custom searches for relay attributes. Unless someone else wants to implement that, feel free to fork it!

Firejail with Tor HOWTO

A few years ago I created a set of scripts to start applications inside a linux namespace and automatically “Tor-ify” their network traffic. The main reason behind this effort was to provide some isolation and Tor support for applications that don’t have socks5 support, for example claws-mail. While this worked it was hard to keep adding sandboxing features like the ones firejail already provided. So I decided to take a look at how I could automatically send/receive traffic from a firejail-ed application through Tor.

This blog post is NOT meant to be used as copy/paste commands but to explain why each step is needed and how to overcome the problems found in the path.
If you have reasons to proxy all your traffic through Tor as securely as possible use Tails on a different machine, this guide is NOT for you.

A dedicated bridge
First of all create a Linux bridge and assign an IP address to it. Use this bridge to attach the veth interfaces that firejail creates when using the ‘net’ option. This option creates a new network namespace for each sandboxed application.

# brctl addbr tornet
# ip link set dev tornet up
# ip addr add dev tornet

Then enable NAT from/to your “external” interface (eno1 in my case) for tcp connections and udp port 53 (DNS) and enable IP(v4) forwarding, if you don’t already use it. Some rules about sane default policy for FORWARD chain are added here well, modify to your needs.

# sysctl -w net.ipv4.conf.all.forwarding=1
# iptables -P FORWARD DROP
# iptables -A INPUT -m state --state INVALID -j DROP
# iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -A FORWARD -i tornet -o eno1 -p tcp -j ACCEPT
# iptables -A FORWARD -i tornet -o eno1 -p udp --dport=53 -j ACCEPT
# iptables -t nat -A POSTROUTING -s -o eno1 -j MASQUERADE

This configuration is enough to start a sandboxed application that will have it’s traffic NAT-ed from the Linux host.

$ firejail --net=tornet /bin/bash
Parent pid 26730, child pid 26731

Interface        MAC                IP               Mask             Status
lo                                UP    
eth0             72:cc:f6:d8:6a:09    UP    
Default gateway

$ host has address
Host not found: 3(NXDOMAIN)
Host not found: 4(NOTIMP)
$ host has address
$ curl

(where is your real IP and should be the IP address of the final DNS recursive resolver requesting information from

So NAT works and the shell is sandboxed.

“Tor-ify” traffic
Edit /etc/tor/torrc and enable TransPort and VirtualAddrNetwork Tor features to transparently proxy to the Tor network connections landing on Tor daemon’s port 9040. DNSPort is used to resolve DNS queries through the Tor network. You don’t have to use IsolateDestAddr for your setup, but I like it.

TransPort 9040
DNSPort 5353 IsolateDestAddr

Then use iptables to redirect traffic from tornet bridge to TransPort and DNSPort specified in torrc. You also need to ACCEPT that traffic in your INPUT chain if your policy is DROP (it is right ?)

# iptables -t nat -A PREROUTING -i tornet -p udp -m udp --dport 53 -j DNAT --to-destination
# iptables -t nat -A PREROUTING -i tornet -p tcp -j DNAT --to-destination
# iptables -A INPUT -i tornet -p tcp --dport 9040 -j ACCEPT
# iptables -A INPUT -i tornet -p udp --dport 5353 -j ACCEPT

Run your sandbox again and try to access the same website:

$ firejail --net=tornet /bin/bash
$ curl
curl: (7) Failed to connect to port 80: Connection timed out

aaaand nothing happens. The problem is that you have tried to route traffic from a “normal” interface to loopback which is considered a “martian” and is not allowed by default by the Linux kernel.

sysctl magic
To enable loopback to be used for routing the route_localnet sysctl setting must be set.
# sysctl -w net.ipv4.conf.tornet.route_localnet=1

Try again:

$ firejail --net=tornet /bin/bash
$ host has address
Host not found: 3(NXDOMAIN)
Host not found: 4(NOTIMP)
$ curl
$ host domain name pointer

it works!

You can actually run any program you want like that:
$ firejail --net=tornet google-chrome

Accessing onion services
There’s one problem left though, accessing onion services.
If you try and access onion service from your firejail+tor setup you will get an error.

$ firejail --net=tornet /bin/bash
$ curl http://sejnfjrq6szgca7v.onion/
curl: (6) Could not resolve host: sejnfjrq6szgca7v.onion

To fix that you need to modify /etc/tor/torrc again and add AutomapHostsOnResolve option.
AutomapHostsOnResolve 1

$ firejail --net=tornet /bin/bash
$ curl -I http://sejnfjrq6szgca7v.onion/
HTTP/1.1 200 OK
Date: Fri, 09 Dec 2016 12:05:56 GMT
Server: Apache
Content-Location: index.en.html
Vary: negotiate,accept-language,Accept-Encoding
TCN: choice
Last-Modified: Thu, 08 Dec 2016 15:42:34 GMT
ETag: "3a40-543277c74dd5b"
Accept-Ranges: bytes
Content-Length: 14912
Cache-Control: max-age=86400
Expires: Sat, 10 Dec 2016 12:05:56 GMT
X-Clacks-Overhead: GNU Terry Pratchett
Content-Type: text/html
Content-Language: en

Accessing onion services works as well now.

Applications supporting socks5
If you already have some of your applications proxying connections to tor using then you need to add another iptables rule to redirect the socks traffic from inside firejail’s namespace to Tor SocksPort.
# iptables -t nat -A PREROUTING -i tornet -p tcp -m tcp --dport 9050 -j DNAT --to-destination

Update on the state of STARTTLS support of Greek email providers

2 months ago I wrote a blog post describing the really bad state of STARTTLS support of Greek email providers. Things have slightly gotten better since then.

Updates on STARTTLS support per provider
The following is current as of 2016/03/26 and are only the updates since the previous blog post.
FORTHNET: Supports TLS 1.2 (at least since 2016/02/03)
VODAFONE: Supports TLS 1.2 for but NOT for (at least since 2016/03/10)

Updates on Certificate status per provider (that have STARTTLS support)
FORTHNET: uses a valid certificate (a wildcard *
VODAFONE: uses a valid certificate (a wildcard *
MAILBOX: uses a valid signed certificate (for (at least since 2016/03/26)

No other changes have been observed.

These updates indicate that 3 out of 5 commercial Greek ISPs currently use STARTTLS on their mail servers, OTE/COSMOTE, Forthnet and Vodafone. Way better than 1 out 5 which was the case 2 months ago. That means that the only ones left behind are Wind and Cyta, Since HOL has merged with Vodafone.

P.S. Thanks fly to @stsimb for notifying me of Forthnet updates with a comment on my blog

The sorry state of STARTTLS support of Greek email providers

I started looking into the STARTTLS support of Greek email providers completely by accident when one email of mine wasn’t being delivered for some reason to a friend who has an email address at a traditional Greek ISP. I started looking into the delivery issues by running swaks against the email server of the ISP and I just couldn’t believe it that the ISP’s mail server response did not include STARTTLS support. That made me wonder about the rest of the ISPs, so I created a very simple script that takes domains, finds their MX addresses and performs very simple TLS lookups using openssl. Yeah I know that there are websites that track the STARTTLS support of mail servers, but they usually don’t save the previous results and you can’t grep and compare.

What I’ve looked into is how emails are sent between servers (SMTP), not if users can read emails from the mail servers (POP3/IMAP) using encrypted connections.

The situation is BAD, REALLY BAD. Only 1,5 (yes, this is one and a half) commercial ISPs supports STARTTLS. OTE/COSMOTE has “proper” STARTTLS support while Wind has STARTTLS support only for domain, but not for their

I couldn’t believe the situation was SO, SO BAD before looking at the results. It seems that I had a lot more faith in those providers than I should have. Yeah I was wrong once again.

wtf is STARTTLS?
(please don’t read the next sentence if you know what TLS is)
If you have no idea about TLS and STARTTLS, then consider STARTTLS a way for servers to communicate and exchange data in encrypted form instead of cleartext. If mail servers don’t support STARTTLS then other servers can’t send them emails in encrypted form and everyone between those 2 servers can read the emails. It’s the equivalent of “https://” for mail servers. (There, I said it…).

TLS support per provider
The following is current as of 2016/01/23

Commercial Providers
OTE/COSMOTE: Some servers support TLS version 1.0 and some others 1.2 (more on that later)
WIND: Supports TLS version 1.0 on but does NOT support TLS on (different mail servers)
CYTA: Does NOT support TLS on their mail servers
FORTHNET: Does NOT support TLS on their mail servers
HOL: Does NOT support TLS on their mail servers
VODAFONE: Does NOT support TLS on their mail servers

non-Commercial Providers
GRNET: Supports TLS 1.2
SCH: Supports TLS 1.0
TEE: Does NOT support TLS on their mail servers
MIL: Supports TLS 1.0

AUTH: Supports TLS 1.2
NTUA: Some servers support TLS 1.0 and one supports TLS 1.2
UPATRAS: Supports TLS 1.0

Free Providers
IN: Does NOT support TLS on their mail servers
FREEMAIL: Does NOT support TLS on their mail servers
MAILBOX: Supports TLS 1.2

Radical Providers
ESPIV: Supports TLS 1.2

Certificate status per provider (that have STARTTLS support)
OTE/COSMOTE: * mail servers, which are the ones that support TLS 1.0, use a certificate that is valid for, * mail servers have their own certificates, but all mail* mail servers, which are the ones that use TLS 1.2, use the same self-signed certificate.
WIND: uses a valid certificate
GRNET: uses a valid certificate
SCH: uses a self-signed certificate (which has expired 5 years ago) signed by their own CA (which has expired 4 years ago)
MIL: uses a self-signed certificate (which has expired 1 year ago) signed by their own CA
AUTH: uses a certificate signed by their own CA called HARICA, whose certificate is now included in modern OSes, so I will consider this a valid certificate.
NTUA: all mail servers use a certificate that is valid for
UPATRAS: uses a valid certificate
MAILBOX: uses a self-signed certificate (by plesk)
ESPIV: uses a valid certificate (a wildcard *

Why does it matter
It makes a huge difference for users’ privacy. If a mail server does not support STARTTLS then anyone with the ability to look into packets traveling on the net from a source mail server to the destination mail server can read the emails in pure plaintext, as you read them on your mail client. Support of STARTTLS for a mail server forces an adversary that previously just passively monitored traffic to have to start a MITM (Man in the middle) attack in order to read those same emails. This converts the adversary from a passive to an active attacker. And this is both expensive and dangerous for the adversary, it can get caught in the act.

Security and privacy-minded people might start bashing me on my next proposal, but considering the current situation I think it’s OK for most of the users of those providers that don’t support TLS at all.
Dear providers, please install a certificate, even a self-signed one, and add support for STARTTLS on your mail servers today.

Even a self-signed certificate improves this situation. And it costs absolutely nothing. There’s really no excuse to not even have a self-signed certificate for your email server.

Self-signed vs CA-Signed
Truth is that it 99.9999% of email servers on the Internet do not verify the remote end’s certificate upon communication. That means that it makes absolutely no difference in most cases whether the certificate is CA-signed or self-signed. Most modern email servers support fingerprint verification for remote servers’ certificates but this can’t obviously scale on the Internet. If a user fears that some entity could MITM their email provider just to read their email, they already have bigger problems and certificate verification would not be able to help them a lot anyway. They either need to protect the contents of their email (gpg?) or start using alternate means of messaging/communication (pond?)

The script I used is on github: gr-mx. Feel free to make changes and send pull requests.
I plan to run the script once a week just to keep an archive of the results and be able to track and compare. Let’s see if something changes…

Various weirdness
* has 2 MX records, and has been unreachable since I started running the script on 2016/01/08.
* mail{5,6,7,8} mailservers used by OTE/COSMOTE did not have the self-signed certificate on 2016/01/08 while mail{1,2,3,4} had it. The certificate was added at some point between 2016/01/11 and 2016/01/17

επισκόπηση της λογοκρισίας στο Ελληνικό Internet

Οι περισσότεροι χρήστες του Ελληνικού Internet αν ρωτηθούν για το κατά πόσο υπάρχει, κρατική ή μη, λογοκρισία σήμερα μάλλον θα απαντήσουν αρνητικά. Η λογοκρισία τη σύγχρονη εποχή δυστυχώς είναι πολύ πιο ύπουλη από ότι στο παρελθόν. Πολλές φορές δεν ξέρουμε καν ποιος είναι ο λογοκριτής και γιατί κάτι είναι απαγορευμένο. Η λογοκρισία, μέρος της οποίας είναι οι κανόνες απαγόρευσης επίσκεψης ή χρήσης συγκεκριμένων sites, ζει και βασιλεύει σήμερα στην Ελλάδα. Όμως, λόγω της ανοργάνωτης δομής του κράτους του ίδιου και η λογοκρισία είναι το ίδιο ανοργάνωτη: όποιος μπορεί λογοκρίνει ό,τι μπορεί αρπάζοντας την ευκαιρία που βρίσκει μπροστά του.

Το Internet στην Ελλάδα δεν είναι κρατικό, ούτε υπάρχει ένας φορέας που να ελέγχει το που συνδέονται οι χρήστες, οπότε η επιβολή των όποιων περιορισμών πρέπει να γίνεται αποκλειστικά από τους παρόχους Internet, πχ Cosmote,Forthnet,Vodafone,κτλ. Οι πάροχοι παίζουν τεράστιο ρόλο στην επιβολή λογοκρισίας, είναι αυτοί που καλούνται από τα δικαστήρια να υπερασπιστούν την μη-επιβολή κανόνων αλλά και αυτοί που πρέπει να αμφισβητήσουν ή να ερμηνεύσουν τα νομικά κείμενα που τους στέλνουν διάφορες αρχές/οργανισμοί/κτλ για να εφαρμόσουν. Μέχρι ένα σημείο είχαν/έχουν και οικονομικό κίνητρο να μην εφαρμόζουν μεθόδους λογοκρισίας γιατί η διαχείριση και λειτουργία μηχανημάτων και φίλτρων σε αυτά, που σκοπό έχουν μόνο την λογοκρισία, είναι για τους παρόχους οικονομική επιβάρυνση. Επίσης αν δεν υπάρχει φορέας που να επιβάλει την τήρηση των ίδιων κανόνων λογοκρισίας από όλους τους παρόχους, τότε ο πιο “ελαστικός” πάροχος θα αρχίσει να παίρνει τους χρήστες που φεύγουν από τους υπόλοιπους παρόχους. Όσο πιο “μεγάλος” είναι ένας πάροχος τόσο περισσότερο υποχρεώνεται να είναι τυπικός στις λογοκριτικές του υποχρεώσεις. Από την στιγμή όμως που οι πάροχοι υποχρεωθούν να βρουν (τεχνικούς) τρόπους λογοκρισίας των χρηστών, τότε το οικονομικό βάρος το έχουν ήδη επωμιστεί και άρα δεν έχουν ισχυρούς λόγους να συνεχίσουν να υπερασπίζονται τους χρήστες με το ίδιο πάθος όπως έκαναν παλιά. Και αυτό ακριβώς συμβαίνει σήμερα πλέον.

Ποιοι έχουν επιβάλει λογοκρισία μέχρι σήμερα στο Ελληνικό Internet όμως και πως; Τα παρακάτω σίγουρα δεν είναι η πλήρης εικόνα του τι έχει συμβεί τα τελευταία χρόνια αλλά έχω πιάσει μερικά κομμάτια που τα θεωρώ ενδεικτικά της αρρωστημένης κατάστασης που επικρατεί.

Τα δικαστήρια
Καταρχήν τα Ελληνικά δικαστήρια με την απόφαση 4658/2012 δημιούργησαν τις πρώτες 2 “τρύπες” στο Ελληνικό Internet. Οι πάροχοι σύμφωνα με την απόφαση υποχρεώθηκαν να κόψουν από τους routers τους την πρόσβαση προς τις IPs και Ακόμα και σήμερα, οι 2 συγκεκριμένες IPs δεν είναι προσβάσιμες (εμφανίζονται * * * = δεν φεύγουν πακέτα μετά τους routers της Cosmote):

$ traceroute
traceroute to (, 30 hops max, 60 byte packets
 5 (  56.557 ms  56.559 ms  60.387 ms
 6 (  56.533 ms  37.518 ms  20.960 ms
 7 (  22.777 ms  27.164 ms  28.518 ms
 8  * * *
 9  * * *

ενώ για μια “διπλανή” IP η πρόσβαση είναι ελεύθερη, φεύγουν πακέτα πέρα από την Cosmote:

$ traceroute
traceroute to (, 30 hops max, 60 byte packets
 4 (  30.735 ms  34.759 ms  35.376 ms
 5 (  77.951 ms  78.097 ms  78.749 ms
 6 (  92.460 ms (  82.512 ms (  82.938 ms
 7 (  80.490 ms  82.161 ms  78.793 ms
 8 (  99.192 ms  78.622 ms  76.786 ms
 9 (  111.910 ms  111.919 ms  115.771 ms
10 (  125.109 ms  118.581 ms 118.586 ms

Δεν υπάρχει χρονικό όριο το πότε θα αρθεί αυτός ο περιορισμός. Αν δεν αποφασίσει κάποιο άλλο δικαστήριο για την άρση του, θα μείνει για πάντα. Και αυτή τη στιγμή δεν λειτουργεί κάποιο “παράνομο” website στους 2 servers αυτούς, ό,τι και να τρέχει εκεί πλέον οι Έλληνες χρήστες δεν μπορούν να το δουν.

Ο μεγαλύτερος μέχρι σήμερα λογοκριτής στην Ελλάδα είναι όμως η ΕΕΕΠ. Ο φορέας που κατάφερε και έγινε ανεξάρτητη αρχή και σιγά σιγά απέκτησε το δικαίωμα να κόβει όποιο site δεν έχει άδεια στοιχηματζίδικου στην Ελλάδα. Το κατά πόσο αυτό έχει νόημα είναι μια άλλη, τεράστια, κουβέντα, αλλά σήμερα η ΕΕΕΠ έχει την εξουσία να υποχρεώνει τους παρόχους να κόβουν 438 διαφορετικά sites στοιχηματικού ενδιαφέροντος που αναφέρονται στην blacklist της. Το γεγονός πως δεν αναφέρουν όλοι οι πάροχοι το πως κάνουν αυτό το κόψιμο (τεχνικά) και το γιατί δεν έκοβαν (ή δεν κόβουν ακόμα) όλοι οι πάροχοι όλα τα sites της blacklist έχει μελετηθεί στην έρευνα EEEP and Greek Internet censorship (δυστυχώς ακόμα εκκρεμεί η Ελληνική μετάφραση καθώς και μια επικαιροποίηση της έρευνας).

Παράδειγμα λογοκρισίας (DNS manipulation) ενός site μέσα από την blacklist της ΕΕΕΠ από την Cosmote ( είναι ένας DNS server της Cosmote):

$ dig @ +short
$ dig -x +short

Οι δύο παραπάνω εντολές αυτές δείχνουν πως η Cosmote έχει γυρίσει τις DNS απαντήσεις για το site σε ένα δικό της server ( Περισσότερα γι’ αυτό παρακάτω.

Η υπόθεση με τα φάρμακα
Για να μπορέσουν οι πάροχοι να υπακούσουν στις προσταγές της ΕΕΕΠ εγκατέστησαν συστήματα περιορισμού της πρόσβασης των χρηστών, πχ DNS manipulation, DPI (Deep Packet Inspection), κτλ. Τι γίνεται όταν υπάρχουν ήδη τέτοια συστήματα ενεργά; Αρχίζει ο καθένας και τα χρησιμοποιεί όπως τον βολεύει. Ωραιότατο παράδειγμα το http://αγοραβιαγκρα.com ( το οποίο δεν άρεσε στο Πανελλήνιο Φαρμακευτικό Σύλλογο και έτσι έστειλαν επιστολή προς Υπουργείο Υγείας, Διεύθυνση Ηλεκτρονικού Εγκλήματος (ΔΗΕ), ΕΕΤΤ λέγοντας πόσο δεν τους αρέσει που υπάρχει ένα ηλεκτρονικό φαρμακείο και πως πρέπει να παρθούν τα νόμιμα μέτρα. Έπειτα οι ISPs φαίνεται πως έκοψαν την πρόσβαση στο site αυτό χωρίς να υπάρχει απόφαση δικαστηρίου (τουλάχιστον κάποια που να έχει ανακοινωθεί)!!! Φήμες φέρουν την ΔΗΕ να επικοινώνησε με τους ISPs και να τους ζήτησε να κόψουν το συγκεκριμένο site. Με ποια αρμοδιότητα βέβαια αποφασίζει ένα τμήμα της αστυνομίας ποιος θα βλέπει τι στο Internet είναι μια πάρα πολύ καλή ερώτηση για τους νομικούς. Αν κάποιος έχει κάποια απόφαση δικαστηρίου, πχ ασφαλιστικά μέτρα που κέρδισε ο ΠΦΣ για την συγκεκριμένη υπόθεση ας το στείλει στα comments.

Πως απέκλεισε η Cosmote το αγοραβιαγκρα.com; με τον ίδιο τρόπο που αποκλείει και τα sites της blacklist της ΕΕΕΠ, αλλάζοντας τις DNS απαντήσεις:

$ dig +short @
$ dig -x +short @

ενώ η σωστή απάντηση είναι:

$ dig +short @

να και το screenshot από αυτό που αντικρίζει κανείς όταν επισκέπτεται το αγοραβιαγκρα.com από σύνδεση Cosmote:

Η εξήγηση που αναγράφει η σελίδα είναι για γέλια και για κλάματα. Αφορά διακοπή πρόσβασης σε site που “προσομοιάζει υπηρεσία του ομίλου ΟΤΕ”. Ο ΟΤΕ δεν πουλάει φάρμακα από όσο ξέρω. Τσαπατσουλιά φουλ. Καμία αναφορά στο ποιος επέβαλε την απαγόρευση και γιατί. Δεν μπορείς να το δεις το site…γιατί έτσι.

Το αν είναι παράνομο να αγοράζει κανείς φάρμακα από ένα website είναι τελείως ασύνδετο με το ποιος αποφασίζει για την απαγόρευση της πρόσβασης στο website αυτό και την σωστή ενημέρωση των χρηστών για τους λόγους απαγόρευσης πρόσβασης. Δεν μπορεί αυτές οι αποφάσεις να παίρνονται ούτε από κάποιον σύλλογο ούτε και από την αστυνομία. Θα έπρεπε να υπάρχει τουλάχιστον κάποιο link προς την απόφαση του δικαστηρίου (αν υπάρχει) που να εξηγεί το σκεπτικό της απαγόρευσης της πρόσβασης.

Η πιο κρίσιμες ερωτήσεις για μένα όμως είναι:
α)Πόσα άλλα sites σαν το αγοραβιαγκρα.com άραγε ανακατευθύνει η Cosmote, αλλά και ο κάθε άλλος πάροχος, σε σελίδα που απλά λέει πως απαγορεύεται η πρόσβαση;
β) Ποιος ακριβώς διέταξε τις απαγορεύσεις αυτές;

Τι άλλο μπορεί να κάνει η ΕΕΕΠ για να βελτιώσει την εξουσιαστική της θέση; να ξέρει πόσοι (και ποιοι) χρήστες προσπαθούν να επισκεφτούν τα sites που διατηρεί στην blacklist της. Βέβαια, το να υποχρεώσει τους παρόχους να δώσουν στοιχεία από τα DNS queries που υποχρεώνονται να χειραγωγούν είναι αρκετά επίπονη τεχνικά εργασία, αλλά υπάρχει απλούστερη λύση. Κάθε πάροχος να κάνει το DNS manipulation των απαντήσεών που δίνει προς ένα δικό του server, η Cosmote για παράδειγμα το κάνει προς το server με IP, και έπειτα εκεί σε HTTP επίπεδο να ανακατευθύνει τους χρήστες προς τον webserver της ΕΕΕΠ, σε μια συγκεκριμένη σελίδα. Έτσι η ΕΕΕΠ μπορεί να εξάγει με άνεση ό,τι στατιστικά θέλει από την επισκεψιμότητα αυτής της σελίδας.

Επίσκεψη από σύνδεση Cosmote προς και αυτόματη ανακατεύθυνση προς ΕΕΕΠ->

$ curl -I
HTTP/1.1 302 Found
Date: Tue, 05 Jan 2016 13:15:29 GMT
Server: Apache
Connection: close
Content-Type: text/html; charset=iso-8859-1

Με αυτό τον τρόπο η ΕΕΕΠ πλέον γνωρίζει ποια IP χρήστη και ποια ώρα προσπάθησε να επισκεφτεί ένα “απαγορευμένο” site. Η επόμενη κίνηση λογικά θα είναι να διατάζει και άρση απορρήτου για όσους προσπαθούν να επισκεφτούν συχνά τέτοια sites. Υπάρχει ένα τεράστιο θέμα όμως εδώ, ο νόμος δεν υποχρεώνει τους παρόχους να ανακατευθύνουν τους πελάτες στους στο site της ΕΕΕΠ, ούτε να δίνουν στατιστικά στοιχεία για το πόσες επισκέψεις κάνει ο καθένας, παρόλα αυτά η ΕΕΕΠ το ζήτησε και οι πάροχοι συμμορφώθηκαν. Το γιατί είναι εντελώς ανεξήγητο.

Το ζοφερό μέλλον
Επειδή τέτοια ζητήματα δεν γίνεται φυσικά να έχουν καμιά θετική εξέλιξη στο πέρασμα του χρόνου, παρά μόνο αρνητική, να τι φέρνει ο νέος νόμος για τη συλλογική διαχείριση δικαιωμάτων πνευματικής ιδιοκτησίας όπως έχει αναρτηθεί σε δημόσια διαβούλευση αυτή τη στιγμή στο Internet. Στο άρθρο 69 παράγραφος 8 μας φέρνει την “Επιτροπή για τη γνωστοποίηση διαδικτυακής προσβολής δικαιωμάτων πνευματικής ιδιοκτησίας και συγγενικών δικαιωμάτων” όπου η πενταμελής αυτή επιτροπή θα έχει 2 μέλη του ΟΠΙ (Οργανισμός Πνευματικής Ιδιοκτησίας), ένα της ΕΕΤΤ (Εθνική Επιτροπή Τηλεπικοινωνιών & Ταχυδρομείων) και 2 δικαστές. Να βάλουμε τους λύκους να φυλάνε τα πρόβατα δηλαδή. Αυτή η επιτροπή ενημερώνει παρόχους Internet και παρόχους υπηρεσιών φιλοξενίας για την παραβίαση πνευματικών δικαιωμάτων από χρήστες τους και τους καλεί να απομακρύνουν το περιεχόμενο. Αν δεν συμμορφωθούν επιβάλει πρόστιμα. Τα παραπάνω τα φέρνει το ίδιο κόμμα που το 2010 είχε βγάλει ανακοίνωση υποστήριξης του αλλά φυσικά το 2015 αποφάσισαν να τσακώσουν τους διαχειριστές του

Future Blacklists
Ε το μόνο που μας μένει είναι να αποκτήσουμε μια επιτροπή, ανεξάρτητη αρχή, ή όπως αλλιώς θα ονομάζεται που να αποφασίζει πως για λόγους ηθικής τάξης θα πρέπει να κόβονται websites. Ή ακόμα καλύτερα να κόβονται sites γιατί προωθούν την “τρομοκρατία”. Για το καλό μας πάντα. Αν ήταν λίγο πιο γάτες εκεί στο Υπουργείο Οικονομικών θα έβγαζαν blacklist ώστε όσα μαγαζιά έχουν eshop και δεν πληρώνουν ΦΠΑ και φόρους να τους κόβουν από το Internet. Πριν 2-3 χρόνια συνέλαβαν το γέροντα Παστίτσιο για βλασφημία, δεν θα μου κάνει καμία εντύπωση να δούμε και καμιά blacklist από την Εκκλησία της Ελλάδος για την προστασία των πιστών…

Τα παραπάνω φαίνονται αστεία, όσο αστείο ήταν παλιά πως θα υπήρχε κάποια επιτροπή που θα αποφάσιζε που επιτρέπεται να χάνει κάποιος τα λεφτά του.

Η αδράνεια
Το πιο στενάχωρο για μένα είναι η πλήρης αδράνεια των χρηστών να εναντιωθούν σε όλα τα παραπάνω. Δεν υπάρχει καμία οργανωμένη αντίδραση. Ούτε καν κείμενα σχολιασμού.
Το HELLUG έχει πλέον ελάχιστα ενεργά μέλη και δεν είναι πλέον σε θέση να εκφράσει απόψεις και να στηρίξει δράσεις όπως το έκανε στο παρελθόν με το
Η ΕΕΧΙ επίσης δεν εκφράζει δημόσιο λόγο (δεν ξέρω αν έχει καν μέλη πλέον).
Το adslgr δεν βλέπω να μπορεί να οργανώσει κάτι, το να γράφουν μερικοί κάποια εκνευρισμένα posts σε ένα forum δεν αρκεί ούτε και αλλάζει κάτι.
To DLN είναι σχεδόν νεκρό και πλέον δεν έχει τις δυνάμεις να σχολιάζει καν τα όσα συμβαίνουν. Η mailing list λειτουργεί αλλά έχει ελάχιστη κίνηση. Παρόλα αυτά είναι μάλλον το μοναδικό σημείο ενημέρωσης για τέτοια ζητήματα.
To Collision Resistance δεν κατάφερε καν να ξεκινήσει.

Υπάρχει μια γενικότερη παραίτηση του κόσμου γύρω από τα θέματα αυτά, ίσως φυσικό αποτέλεσμα των όσων συμβαίνουν γενικότερα στην Ελλάδα τα τελευταία χρόνια.

“Ε δεν πειράζει μωρέ, τι χειρότερο μπορεί να συμβεί;” Τα καλύτερα έρχονται!

* Bonus *
Η αποφυγή
Ο πιο εύκολος τρόπος να αποφύγει κανείς κάθε περιορισμό που έχει τεθεί μέχρι σήμερα είναι να χρησιμοποιήσει κάτι σαν το Tor. Δεν χρειάζεται ούτε να αλλάξει DNS servers, ούτε να αγοράσει VPN. Κατεβάζει τον Tor Browser και συνεχίζει ό,τι έκανε παλιά σαν να μην συμβαίνει τίποτα. Ο δρόμος αυτός όμως είναι και επικίνδυνος, αν αφήσουμε την προσβασιμότητα στο Internet στο πόσο καλά λειτουργούν 1-2 εργαλεία δεν θα αργήσει να έρθει η ώρα που ακόμα και αυτά δεν θα αρκούν. Ο σωστός δρόμος είναι να οργανωθούν οι χρήστες σε ομάδες, κοινότητες και οργανώσεις και να εκφράσουν μαζικά τις αντιρρήσεις και αντιδράσεις τους στα παραπάνω. Όχι με tweets και με posts στο Facebook. – A GPG Keyserver in Greece

After some months of entertaining the idea of setting up a public gpg keyserver I finally managed to find some time and do it this weekend.

Habemus Keyserver!

Some history
The first time I set up a gpg keyserver was 3 years ago. Its purpose was to make it possible for a researcher to get more results than the default on a single query from a keyserver. Using that keyserver the Greek PGP Web of Trust 2012 edition was created. After the original import of the keys, I refreshed the keys just 2 or 3 times in the following years.

The setup
The keyserver is running on Debian Linux with SKS version 1.1.5. Port 80 and 443 are being handled by nginx which acts as a reverse proxy for SKS. I originally had port 11371, the default port that gpg client uses, behind nginx as well but I had to remove it due to the following issue. I like using HSTS header for the HTTPS port, but browsers trying to access, were switching to (because of HSTS) which couldn’t work because port 11371 does not use TLS. So once a browser visited and got the HSTS header, every future connection towards would fail. The solution was to use a protocol multiplexer called sslh. What this does, is that it sniffs the connections coming towards port 11371 and if it finds a TLS connection, it sends it to port 443, if it finds an HTTP connection it sends it to port 80. That way you can either visit or and they both work.

For ports 80,443 the connection path looks like: client -> nginx -> sks
For port 11317 the connection path looks like: client -> sslh -> nginx -> sks is available in both IPv4 and IPv6.

I’ve also setup an onion/hidden service for the keyserver, so if you prefer visiting the onion address, here it is: wooprzddebtxfhnq.onion (available on port 11371 as well).

I’m not sure if it’s the Debian package’s fault or I did something stupid, but if you plan on running your own keyserver be very careful with permissions on the your filesystem. sks errors are not very friendly. Make sure that /var/spool/sks, /var/lib/sks and /var/log/sks are all owned by debian-sks:debian-sks.
# chown -R debian-sks:debian-sks /var/spool/sks /var/lib/sks /var/log/sks
Don’t run the DB building script as root, run it as debian-sks user:
# sudo -u debian-sks /usr/lib/sks/
There are a quite some tunables referenced in the sks man page regarding pagesizes, I went with the default options for now.

The pool
To enter the pool of keyservers and start interacting with other keyservers you have to join the sks-devel mailing list and announce your server existence by sending your “membership line” which looks like this: 11370 # George K. <keyserver [don't spam me] void [a dot goes here] gr> #0x721006E470459C9C

If people place this line in their membership config file and you place theirs, then the keyservers start communicating, or “gossiping” as it is called in the sks language. It needs to be mutual.

Because of the minimal traffic I was seeing on the mailing list archives I thought that finding peers would take weeks, if not months. I was very very wrong. I got 6 replies to my email in less than 2 hours. Impressive. Thanks a lot people!

I’ve taken the boostrap-ed HTML from

hkps support will be added in the following days or weeks.

Stats Keyserver statistics pool Status for


Ασφαλιστικά μέτρα ΑΕΠΙ κατά παρόχων 2015

Έχει αρχίσει να καταντάει βαρετό ίσως αλλά η ΑΕΠΙ αποφάσισε να μας απασχολήσει και φέτος. Συγκεκριμένα καταθέτει νέα ασφαλιστικά μέτρα κατά των παρόχων:

  • Vodafone
  • Forthnet
  • HOL
  • Wind
  • Cyta
  • OTE
  • OnTelecoms
  • NetOne

(Μα NetOne και OnTelecoms; που τους θυμήθηκαν…)

ζητώντας τους να αποκλείσουν με διάφορους τρόπους την πρόσβαση των συνδρομητών τους προς τα παρακάτω sites/domains:


(δεν ήξερα ούτε ένα από αυτά τα sites…τι μαθαίνει κανείς…)

Με ποιους τρόπους ζητάει αυτή τη φορά τον αποκλεισμό η ΑΕΠΙ;

  • DNS Block
  • Router ACLs
  • Αποκλεισμό περιεχομένου

Το ζουμί είναι πως για πρώτη φορά η ΑΕΠΙ αναφέρει πως αν δεν μπορούν οι πάροχοι να κόψουν την πρόσβαση προς τα domains ή τις IPs να κόψουν την “παράνομη καταφόρτωση-αναπαραγωγή ή/και ανταλλαγή των μουσικών έργων” ή να πετύχουν “άρση των συγκεκριμένων προσβολών που λαμβάνουν χώρα στις ιστοσελίδες”. Για να γίνει οποιοδήποτε από τα παραπάνω ο πάροχος θα πρέπει να παρακολουθεί το περιεχόμενο της κίνησης κάθε συνδρομητή, άρα μιλάμε για μια λύση τύπου Deep Packet Inspection (DPI), ανάλογη με αυτή που εφαρμόζει η Vodafone για να περιορίσει την πρόσβαση στα στοιχηματζίδικα που έχει διατάξει η ΕΕΕΠ. Έχοντας χάσει τα προηγούμενα ασφαλιστικά μέτρα του 2013 στα οποία ζητούσε αποκλεισμό domain ή IP, πλέον η ΑΕΠΙ ζητάει παρακολούθηση και αποκλεισμό περιεχομένου.

Ορίστε και ένα μικρό κομμάτι του κειμένου των ασφαλιστικών μέτρων.






Στα ωραία της υπόθεσης, το γεγονός πως έχουν βάλει μέσα IPs από την Cloudflare. Μεγάλο αυτογκόλ πριν καν αρχίσει το επαναληπτικό (3ο) ματς. Δεν ρώτησαν έναν άνθρωπο τι είναι αυτή η Cloudflare και γιατί εμφανίζεται τόσο συχνά; Την επόμενη φορά θα ζητήσουν να κοπεί η Google και η Amazon.

Δικάσιμος 13/10/2015!

Άλλη μια σημαντική δίκη που έχασε πρόσφατα η ΑΕΠΙ…δεν είναι σε φόρμα τελευταία.
Αθωώθηκαν τέσσερις καταστηματάρχες της Κοζάνης για τις καταγγελίες της ΑΕΠΙ περί πνευματικών δικαιωμάτων (βίντεο)

*Ενημέρωση*: Νέα δικάσιμος 11/11/2015

Κατάργηση ηλεκτρονικών ψηφοφοριών και ψηφιακός αναλφαβητισμός

Στις 08/05/2015 στην βουλή σχολιάστηκαν οι ηλεκτρονικές ψηφοφορίες των πρυτανικών συμβουλίων και ουσιαστικά ο Πρωθυπουργός κ. Τσίπρας υπερασπίστηκε την κατάργησή τους. Το κύριο πρόβλημα (μου) με το παραπάνω είναι οι λόγοι που ισχυρίστηκε η κυβέρνηση πως προχωρά σε κάτι τέτοιο.

Πριν σχολιάσω παραπέρα να δηλώσω πως είμαι από τους ελάχιστους, όταν γινόταν οι ηλεκτρονικές ψηφοφορίες των πρυτανικών ήμασταν 4 άτομα τώρα είμαστε λίγοι παραπάνω, που έχουν πρόσβαση στους servers στους οποίους διεξάγονται οι ηλεκτρονικές αυτές ψηφοφορίες. Δεν έχω γράψει ούτε μια γραμμή κώδικα για το software που τρέχει τις “εκλογές”, αλλά είμαι διαχειριστής των μηχανημάτων, των servers. Η ομάδα στην οποία ανήκω στήνει το λειτουργικό του server, το software που θα τρέξει στο server, συμβουλεύει τους developers για αλλαγές που πρέπει να γίνουν σε θέματα απόδοσης του software, προστατεύει τον server από επιθέσεις, κτλ. System Administrator που λένε και στο χωριό μου, με ολίγο από system engineer και security engineer.

Πριν σχολιάσω τα λόγια του Π/Θ αντιγράφω από τα πρακτικά της Βουλής για τις 08/05/2015 τα ακριβή λόγια της ερώτησης από τον κ. Θεοδωράκη και έπειτα του κ. Τσίπρα, γιατί στα περισσότερα sites είναι σχετικά διαστρεβλωμένα:


Έχουμε την πρόθεση να καταργηθεί η ηλεκτρονική ψηφοφορία. Υπάρχουν άνθρωποι στον ΣΥΡΙΖΑ –ευτυχώς λίγοι- που μιλούν για τεχνοφασισμό. Είναι τεχνοφασισμός σήμερα η ηλεκτρονική ψηφοφορία; Πού θα επιστρέψουμε, στα περιστέρια, που είναι και λίγο πιο γραφικό;


Έρχομαι στο θέμα της ηλεκτρονικής ψηφοφορίας. Μιλήσατε για την ηλεκτρονική ψηφοφορία και είπατε ότι αυτή διασφαλίζει τη μαζική συμμετοχή.
Είμαι υπέρμαχος της άποψης ότι η χρήση τεχνολογίας πρέπει να γίνει συμβατή με την καθημερινότητα μας. Εάν όμως έχουμε την αντίληψη ότι η ηλεκτρονική ψηφοφορία διασφαλίζει τη συμμετοχή, γιατί δεν την προτείνουμε; Να αντικαταστήσουμε τις εκλογές, να μην κουράζεται ο κόσμος να πηγαίνει στα παραβάν να ψηφίζει, να καταργήσουμε και την ζώσα διαδικασία μέσα στο Κοινοβούλιο και να ψηφίζουμε όλοι από το laptop μας, από τα γραφεία μας.

Εδώ, λοιπόν, πρέπει να βάλουμε κάποιες διαχωριστικές γραμμές. Τόσο καιρό η ψηφοφορία στα πανεπιστήμια γινόταν με τον παραδοσιακό τρόπο. Η μαζικότητα, όχι σε ό,τι αφορά τους φοιτητές, αλλά σε ό,τι αφορά τα μέλη ΔΕΠ ήταν διασφαλισμένη. Ήταν διασφαλισμένη η μαζικότητα. Δεν υπήρχε κανένα θέμα μαζικότητας.

Αυτό που άλλαξε με την ηλεκτρονική ψηφοφορία και ο λόγος που την καταργούμε είναι ο εξής: Με την ηλεκτρονική ψηφοφορία η πραγματική εφορευτική επιτροπή δεν είναι αυτοί που συλλέγουν τα e-mails και αθροίζουν τις ψήφους, είναι ένας server, τον οποίο κανείς μη μυημένος δεν μπορεί να ελέγξει. Επομένως, το αδιάβλητο δεν διασφαλίζεται. Όμως, το ακόμη χειρότερο, κρισιμότερο και ουσιαστικότερο είναι ότι δεν διασφαλίζεται η μυστικότητα. Τα ηλεκτρονικά ίχνη και η προσωπική επιλογή του καθενός είναι εκεί, στη διάθεση του κάθε ενδιαφερόμενου.

(Δεν βρήκα πουθενά στα πρακτικά που/αν στην ερώτηση αναφέρθηκαν τα περί “μαζικής συμμετοχής”…αλλά έστω)

Τα παραπάνω τα είπε ένας νεότατος άνθρωπος που υποτίθεται πως έχει και σχέση με την τεχνολογία, δεν τα είπε ο Ζολώτας ούτε ο Κωνσταντίνος Καραμανλής, τα είπε ο κ. Τσίπρας.

Ας τα πάρουμε κομμάτι κομμάτι.

Καταρχήν είναι παράλογη η σύγκριση της συζήτησης που εξελίσσεται κατά την κοινοβουλευτική διαδικασία με την ψήφο την ίδια. Μήλα με πορτοκάλια. Τι σχέση έχει το ένα με το άλλο; Μπορεί κανείς να συζητά όσες ώρες θέλει, να ακούει όλες τις απόψεις και να ψηφίζει έπειτα ηλεκτρονικά. Είναι καλύτερα να ψηφίζουν διά ανατάσεως χειρός ή δια βοής δηλαδή; Όσες φορές και αν διαβάσω το συγκεκριμένο απόσπασμα της ομιλίας μου φαίνεται τελείως παράλογο.

Έπειτα να δούμε γιατί ήρθαν οι ηλεκτρονικές ψηφοφορίες και τι κρύβεται πίσω από τις λέξεις “μαζική συμμετοχή” της ερώτησης(;) στην οποία απαντά ο κ. Τσίπρας. Οι ηλεκτρονικές ψηφοφορίες ήταν μια εναλλακτική μέθοδος εκλογής των πρυτανικών συμβουλίων σε περίπτωση που οι παραδοσιακές μέθοδοι “δεν λειτουργούσαν”. Ας δούμε τι λέει το ΦΕΚ 2564 – 21/09/2012

Η παρούσα απόφαση ρυθμίζει τον τρόπο οργάνωσης και διεξαγωγής της εκλογικής διαδικασίας ανάδειξης των εσωτερικών μελών του Συμβουλίου και του Πρύτανη των Α.Ε.Ι. μέσω ηλεκτρονικής και επιστολικής ψήφου σύμφωνα με το άρθρο 8 του ν. 4009/2011 (Α ́ 195), όπως τροποποιήθηκε με τον ν. 4076/2012 (Α ́ 159), στην περίπτωση δύο διαδοχικών άγονων εκλογικών διαδικασιών

Οπότε για να πάει ένα ΑΕΙ σε ηλεκτρονικές ψηφοφορίες σημαίνει πως ήδη ο παραδοσιακός τρόπος ψηφοφορίας _δεν_ δουλεύει. Γιατί δεν δουλεύει όμως; Τι μπορεί να κάνει μια παραδοσιακή εκλογή άγονη; Στο δικό μου μυαλό ισχύουν τα εξής:

  1. να μην πάει κανείς να ψηφίσει
    • A) γιατί δεν θέλουν
      B) γιατί δεν τους αφήνουν
  2. δεν έχει οργανωθεί σωστά η ψηφοφορία
    • A) δεν υπάρχουν κάλπες
      Β) προβλήματα με την εφορευτική επιτροπή

Το πρόβλημα δεν είναι προφανώς η περίπτωση 1A, αλλά όλες οι υπόλοιπες, στις οποίες θέλει κάποιος να ψηφίσει και δεν μπορεί.

Και πάλι όμως όποιος μένει σε αυτά χάνει το δάσος. Το πρόβλημα εξαρχής δεν ήταν ο τρόπος διεξαγωγής των εκλογών των πρυτανικών συμβουλίων, αλλά το γεγονός πως δεν ήθελε μια μερίδα του κόσμου τα πρυτανικά συμβούλια τα ίδια. Αυτή ήταν η γνώμη τους και την υποστήριζαν με όποιο τρόπο μπορούσαν. Οπότε η τότε κυβέρνηση έκανε ντρίπλα, ξέροντας πως τις κανονικές εκλογές μπορεί κανείς εύκολα να τις σταματήσει, αλλά δεν μπορεί να σταματήσει το ίδιο εύκολα τις ηλεκτρονικές. Έτσι συνέβη το εξής ενδιαφέρον, αυτοί που δεν ήθελαν τα πρυτανικά συμβούλια για τους Χ,Υ,Ζ λόγους, δίκαιους ή άδικους μικρή σημασία έχει για αυτό το κείμενο, αντί να συνεχίσουν να προσπαθούν να υπερασπιστούν την γνώμη τους με επιχειρήματα ενάντια στα πρυτανικά συμβούλια, βρέθηκαν ξαφνικά σε ένα εντελώς διαφορετικό γήπεδο, αυτό των ηλεκτρονικών ψηφοφοριών, και προσπαθούσαν να βρουν επιχειρήματα πλέον για να μην λειτουργήσουν οι ηλεκτρονικές ψηφοφορίες και όχι τα πρυτανικά συμβούλια.

Η ντρίπλα της τότε κυβέρνησης ήταν εμπνευσμένη από κίνηση του Magic Johnson…πέρασε την μπάλα κάτω από τα πόδια του αντιπάλου ο οποίος έμεινε να κοιτάει το άδειο γήπεδο όσο αυτή κάρφωνε.

Οπότε η σημερινή κυβέρνηση θυμάται ακόμα αυτό το….κάρφωμα και πονάει. Δεν αρκείται στην κατάργηση των πρυτανικών συμβουλίων αλλά καταργεί και τις ηλεκτρονικές ψηφοφορίες γενικά. Πονάει χέρι, κόψει…κεφάλι.

Ο παραλογισμός όμως αρχίζει στο δεύτερο σκέλος της απάντησης του κ. Τσίπρα σχετικά με την εφορευτική επιτροπή και τον “server”. Εκεί φαίνεται η τεχνοφοβία και η ένδεια των συμβούλων του περί τεχνολογικών θεμάτων. Γιατί αν είχαν κάτσει να μελετήσουν σοβαρά το ζήτημα, ή αν είχαν ρωτήσει κάποιον σχετικό ερευνητή (όχι κάποιον που ξέρει από γκομπιούτερ, κάποιον ερευνητή γράφω), θα είχαν ίσως βρει πατήματα για να έχουν ενστάσεις για τον τρόπο διεξαγωγής των ηλεκτρονικών ψηφοφοριών, αλλά ΣΙΓΟΥΡΑ δεν είναι αυτά τα σοφίσματα που αναφέρουν.

Το πλέον εξοργιστικό με την κριτική κατά του συστήματος ηλεκτρονικών ψηφοφοριών, Zeus όπως είναι το “project name” του, είναι πως κανείς δεν έχει διαβάσει ποτέ το πως ακριβώς δουλεύει το σύστημα αυτό για να μπορέσει να του ασκήσει σοβαρή κριτική. Μονίμως η κριτική γίνεται πάνω στο πως φαντάζεται κάποιος πως δουλεύει το Zeus. Γι’ αυτό και οι αυθαίρετες ερμηνείες όπως: “ο server τα βλέπει όλα”, “αυτοί έχουν τα κλειδιά και κάνουν ό,τι θέλουν”, “ξέρουν ποιος ψηφίζει και πότε”, κτλ, κτλ. είναι τόσο λάθος. Και δεν χρειάζεται ιδιαίτερος κόπος για να μάθει κανείς γιατί τα παραπάνω είναι όλα λάθος υποθέσεις, αρκεί να διαβάσει το εγχειρίδιο χρήσης και 1-2 σχετικά paper.

Ο “server” λοιπόν, τρέχει ένα λογισμικό ανοιχτού κώδικα το οποίο υλοποιεί μαθηματικούς αλγορίθμους για να εξασφαλίσει την εγκυρότητα της ψήφου, των αποτελεσμάτων και του αδιάβλητου της διαδικασίας. Όλα αυτά φυσικά γίνονται χρησιμοποιώντας κρυπτογραφία (δηλαδή μαθηματικά). Δεν γνωρίζει κανείς τι ψήφισε κάποιος, ούτε αυτοί που έγραψαν το software, ούτε εμείς που διαχειριζόμαστε το server, ούτε η εφορευτική επιτροπή. Και όλα αυτά μπορεί κάποιος να τα αποδείξει μαθηματικά.

“Αδύνατον να συμβαίνει κάτι τέτοιο” θα σκούξουν κάποιοι…έλα όμως πως είναι δυνατόν κάτι τέτοιο όντως να συμβαίνει. Πως να πείσεις τώρα πως δεν είσαι ελέφαντας και πως όλα αυτά είναι πραγματικότητα; Ο κόσμος προοδεύει, αποδεχτείτε το.

Δεν θα γράψω τίποτα το τεχνικό για το πως δουλεύουν όλα αυτά, υπάρχουν αναλυτικά στο site του Zeus άλλωστε, αλλά θα σταθώ στην φράση “τον οποίο κανείς μη μυημένος δεν μπορεί να ελέγξει”. Δηλαδή μας λένε πως επειδή η πλειοψηφία του κόσμου αδυνατεί να κατανοήσει τα μαθηματικά αυτά, να μην τα χρησιμοποιήσουμε. Βάζω στοίχημα πως οι περισσότεροι δεν ξέρουν πως λειτουργεί ένας κινητήρας εσωτερικής καύσης αλλά οδηγούν αυτοκίνητο, ούτε τι κάνει ένα αεροπλάνο να πετάει αλλά το χρησιμοποιούν για τα ταξίδια τους. Οι περισσότεροι χρησιμοποιούν υπολογιστή και Internet κάθε μέρα, αλλά δεν έχουν την παραμικρή ιδέα πως και η ασφάλεια στο Internet βασίζεται ακριβώς στα ίδια μαθηματικά. Γιατί να μην καταργήσουμε και το Internet στην Ελλάδα λοιπόν αφού οι μη μυημένοι δεν καταλαβαίνουν πως λειτουργεί; Δεν υπάρχει χειρότερη δικαιολογία από το “δεν καταλαβαίνω κάτι άρα το καταργώ”. Δεν υπάρχει μεγαλύτερος σκοταδισμός από αυτό. Πραγματικός μεσαίωνας. Αντί για μάγισσες καίμε software, αυτή είναι η μόνη διαφορά. Δεν έχουν που δεν έχουν τα πανεπιστήμια πρόσβαση σε διεθνείς βιβλιοθήκες πλέον, όχι δεν φταίει ο σύριζα γι’ αυτό, φταίνε οι προηγούμενοι, σε λίγο θα πρέπει να ξεχάσουμε και όσα έχουμε ήδη μάθει.

Δεν μπορώ με τίποτα να αποδεχτώ πως ο κ. Τσίπρας, απόφοιτος πολυτεχνείου, πιστεύει όντως αυτό που είπε. Θεωρώ πως το εσωκομματικό του ακροατήριο τον πίεσε να εκδικηθούν για τα πρυτανικά συμβούλια (εεε σόρρυ, τις ηλεκτρονικές ψηφοφορίες) και βρήκαν οι σύμβουλοί του μια (τραγική) δικαιολογία που θα την καταπιούν αμάσητη και οι υπόλοιποι πολιτικοί, γιατί πάσχουν και αυτοί από την ίδια ασθένεια, την τεχνοφοβία, και τα media, γιατί και αυτά έχουν παντελή άγνοια της ψηφιακής πραγματικότητας. Γνωρίζω πως υπάρχουν άνθρωποι στο σύριζα που έχουν τεκμηριωμένες απόψεις για τεχνολογικά ζητήματα, προφανώς κανείς δεν τους πλησίασε και κανείς δεν ζήτησε την γνώμη τους. Αυτό είναι και ένα μεγάλο ζήτημα εδώ, να υπάρχει κόσμος που να είναι τεχνολογικά καταρτισμένος, μυημένος όπως είπε ο κ. Τσίπρας, αλλά οι κομματικοί οργανισμοί να τους αγνοούν πλήρως και να φτάνουν έτσι σε σκοταδιστικά συμπεράσματα.

Αν κάποιος θέλει, μπορεί να πάρει τις (ψηφιακά υπογεγραμμένες) ψήφους και να ξανατρέξει δικούς του αλγορίθμους για να επαληθεύσει όλα τα παλιά αποτελέσματα. Είναι τόσο απλό. Ας το κάνουν, και αν βρουν εσκεμμένα λάθη ας μιλήσουν όσο θέλουν για το διαβλητό ή μη της διαδικασίας. Αλλά κανείς δεν πρόκειται να μπει σε μια τέτοια διαδικασία, γιατί αυτό θέλει κόπο ενώ το να αραδιάζει κανείς σοφίσματα είναι εύκολο.

Και πάμε στο τελευταίο κομμάτι της δήλωσης, που είναι ακόμα πιο προβληματικό από τα προηγούμενα. Εδώ γίνεται νύξη περί του διαβλητού της μυστικότητας. Ποια είναι τα _ακριβή_ ηλεκτρονικά ίχνη στα οποία γίνεται αναφορά; 99% εννοούν την IP του χρήστη κατά την ψηφοφορία…η οποία όμως στο σύστημα Zeus δεν κρατιέται πουθενά μαζί με την ψήφο, ακριβώς για να διασφαλίζεται η μυστικότητα. Για εσένα που σκέφτεσαι πονηρά όσο διαβάζεις αυτό το κείμενο, ούτε το όνομα του κρατιέται, κανένα στοιχείο που μπορεί να συνδυάσει ψήφο με άνθρωπο δεν κρατιέται από το σύστημα. Και πάλι δεν θα κάτσω να αναλύσω πως ακριβώς δουλεύει το Zeus, αλλά είναι προφανές πως το άτομο το οποίο πληροφόρησε τον κ. Τσίπρα είναι στην καλύτερη των περιπτώσεων ημιμαθές (αλλά με μεγάλες άκρες). Θα μπορούσε κάλλιστα ο καθένας να έμπαινε να ψηφίσει μέσω Tor, από το σπίτι του γείτονα, από ένα netcafe, από οπουδήποτε. Δεν έχει καμία σημασία η IP από την οποία μπαίνει κανείς. Η ίδια η ψήφος είναι κρυπτογραφημένη από τον υπολογιστή του χρήστη (browser) πριν φτάσει στο Zeus…αλλά άρχισα τα τεχνικά και ξεφεύγω χωρίς λόγο. Το αδιάβλητο της διαδικασίας και η τήρηση της μυστικότητας είναι ακρογωνιαίος λίθος κάθε σύγχρονου συστήματος ηλεκτρονικής ψηφοφορίας, όχι μόνο του Zeus. Οι ηλεκτρονικές ψηφοφορίες δεν είναι συστήματα που αντί για χαρτί και παραβάν έχεις ένα υπολογιστή, είναι πολύ μα πολύ πιο σύνθετες διαδικασίες, είναι κομμάτι της επιστήμης των μαθηματικών. Αν κάποιου το μυαλό δεν χωράει αυτή την πρόοδο, ας στρωθεί στο διάβασμα.

Αλλά η δήλωση έχει μέσα της άλλο ένα παραλογισμό. Αφού δεν αρέσει καν η υποψία της τήρησης ηλεκτρονικών ιχνών στις ψηφοφορίες, γιατί το κράτος υποχρεώνει τους ISPs να κρατάνε τα δεδομένα σύνδεσης των χρηστών στο Internet για 1 χρόνο; Γιατί υπάρχει καταγραφή των μεταδεδομένων των τηλεφωνικών κλήσεων, ποιος κάλεσε ποιον, τι ώρα, ποια ήταν η διάρκεια της κλήσης, και από που (αν μιλάμε για κινητή τηλεφωνία) για 1 χρόνο; Αυτά δεν είναι ηλεκτρονικά ίχνη γεμάτα με προσωπικές επιλογές του καθενός; Αν δεν αρέσουν τα ηλεκτρονικά ίχνη, και εγώ είμαι σίγουρα ένας από αυτούς που δεν του αρέσουν, καταργήστε τα παντού. Σίγουρα θα έχετε και την δική μου στήριξη σε κάτι τέτοιο.

Τα ηλεκτρονικά ίχνη (IP) τα οποία υπονοήθηκε πως συνδυάζονται με την ψήφο, ενώ διασφαλίζεται με διάφορες μεθόδους του Zeus πως δεν γίνεται αυτό, δεν πρέπει να κρατιούνται κατά την λογική της κυβέρνησης, ενώ τα ψηφιακά ίχνη που συνδυάζονται με όλες τις υπόλοιπες δραστηριότητες των ανθρώπων στον ψηφιακό κόσμο ας κρατιούνται (και δεν μας πειράζει – αφού δεν τα σχολιάζουμε). Τι είδους λογική είναι αυτή;

Επίσης το “στη διάθεση του κάθε ενδιαφερόμενου” της δήλωσης τι υπονοεί; Πως εμείς που λειτουργούμε το σύστημα μοιράζουμε τα δεδομένα σε “κάθε ενδιαφερόμενο”; Αν ναι, αυτό είναι σοβαρή κατηγορία, και θα το πάρω και προσωπικά. Αν έχει κάποιος αποδείξεις ας πάει στα δικαστήρια. Αλλιώς να σταματήσει εδώ και τώρα τα σοφίσματα (για να μην πω τίποτα χειρότερο…). Αν έβγαινα εγώ να κάνω δηλώσεις και να υπαινίσσομαι πράγματα για το διαβλητό της διαδικασίας σε ψηφοφορίες στην Βουλή χωρίς κανένα στοιχείο θα με πήγαιναν στα δικαστήρια ή όχι;

Τέλος, νομίζω αξίζει να αναφέρω ένα ωραίο feature του Zeus που σχετίζεται με αυτό που η αρχική ερώτηση αναφέρει με τις λέξεις “μαζική συμμετοχή” (ενώ στην πραγματικότητα εννοεί κάτι άλλο).
Επειδή υπήρχε στον αέρα η “φήμη” πως με τις παραδοσιακές μεθόδους ψηφοφορίας κάποια μέλη ΔΕΠ έπαιρναν από το χεράκι άλλα μέλη ΔΕΠ, τους έδιναν “σταυρωμένα ψηφοδέλτια” και τους επέβλεπαν την ώρα που ψήφιζαν, το Zeus έχει ένα πολύ ωραίο feature. Μπορεί κάποιος να αλλάξει την ψήφο του όσες φορές θέλει μέχρι να κλείσει η διαδικασία της ψηφοφορίας. Άρα και να σε αναγκάσει κάποιος να ψηφίσεις κάτι με το ζόρι ή να αλλάξεις την ψήφο σου σε μια δεδομένη χρονική στιγμή, ακόμα και αν σε απειλήσει με οποιονδήποτε τρόπο, έχεις την δυνατότητα να την αλλάξεις και πάλι σε αυτό που εσύ θέλεις μόλις αυτός πάψει να σε απειλεί. Και είναι αδύνατον αυτός που απειλεί κάποιον για να αλλάξει την ψήφο του να μπορεί να απειλεί όλο το εκλογικό σώμα ταυτόχρονα μέχρι την λήξη της ψηφοφορίας. Στις παραδοσιακές μεθόδους ψηφοφορίας που δεν μπορείς να αλλάξεις την ψήφο σου, ο εκβιαστής μπορεί να απειλήσει έναν έναν όσους ψηφίζουν την ώρα της ψηφοφορίας και η ψήφος που τελικά θα καταμετρηθεί θα είναι αυτή που έχει έρθει μέσω εκβιασμού και όχι αυτή που ήθελε ο ψηφοφόρος. Γι’ αυτό και μόνο το λόγο θα έπρεπε οι (ηλεκτρονικές) ψηφοφορίες που γίνονται με συστήματα τύπου Zeus να προτιμώνται σε σχέση με τις παραδοσιακές.

Υπάρχει [εδώ] ένα blog post που περιέχει ένα email από τον τότε Αντιπρύτανη του Πανεπιστημίου Κρήτης κ. Τζανάκη που χρησιμοποιεί επιχειρήματα παρόμοια με αυτά που χρησιμοποίησε ο κ. Τσίπρας στην δική του απάντηση. Ημιμάθεια, ψηφιακός αναλφαβητισμός και σκοταδισμός. Και αυτά είναι λόγια αντιπρύτανη…όχι κάποιου τυχαίου.

Θέλουν να καταργήσουν τα πρυτανικά συμβούλια; Θεωρούν πως έχουν κάποια καλύτερη ιδέα για την λειτουργία των πανεπιστημίων; Ας το κάνουν. Θα κριθούν εκ του αποτελέσματος όπως κρίθηκαν και οι προηγούμενοι. Αλλά οι δικαιολογίες που έδωσαν για την κατάργηση των ηλεκτρονικών ψηφοφοριών δεν στέκουν με τίποτα. Και τους κάνουν να φαίνονται ψηφιακά αναλφάβητοι και ημιμαθείς. Το να χρησιμοποιεί κανείς ψευδο-τεχνολογικές δικαιολογίες σίγουρα δεν είναι σοβαρή πολιτική πάντως.

Χαρακτηριστικό του φασισμού είναι η αποστροφή προς την γνώση και τις επιστήμες. Αν λοιπόν με την ίδια αποστροφή αντιμετωπίζει και η σημερινή κυβέρνηση τις ηλεκτρονικές ψηφοφορίες, επειδή δεν είναι “μυημένη”, ποιος τελικά επιβάλει τον (τεχνο)φασισμό;

Έχω τρέξει δεκάδες άλλα προγράμματα/projects όσο εργάζομαι στο grnet και το Zeus ήταν ένα από αυτά που μας προκάλεσαν τους λιγότερους πονοκεφάλους ως software. Ίσως τους περισσότερους στην επικοινωνία με τρίτους ανθρώπους, αλλά γι’ αυτό φυσικά δεν φταίει η ομάδα ανάπτυξης του software. Προσωπικά θεωρώ αρκετά σημαντικό το γεγονός πως από την δουλειά που έγινε βγήκαν papers (πχ “From Helios to Zeus“) και αναγνωρίστηκε η αξία του software σε Ελλάδα και Εξωτερικό. Ακόμα ένα ενδιαφέρον σημείο είναι πως το Zeus χρησιμοποιήθηκε από διάφορους ιδιωτικούς συλλόγους τα τελευταία 2 χρόνια για να κάνουν τις εκλογές τους, έτσι το δημόσιο είχε μέχρι και έσοδα(!) από το Zeus. Γιατί δεν υπάρχει μάλλον, τουλάχιστον ακόμα, κανείς άλλος στην αγορά της πληροφορικής που να μπορεί να φτιάξει και να τρέξει ένα παρόμοιο σύστημα το ίδιο αξιόπιστα. Ε τώρα βέβαια όλο και κάποιος θα βρεθεί να καλύψει το κενό…

Αν κάποιος έχει το email του κ. Τσίπρα ας του στείλει το εγχειρίδιο χρήσης ψηφοφόρου για το Zeus, ίσως το ξανασκεφτεί και δεν μας ρίξει στα ψηφιακά τάρταρα.

Υ.Γ. Προφανώς το παραπάνω post είναι καθαρά προσωπικό (όπως και τα υπόλοιπα στο blog αυτό) και δεν αντιπροσωπεύει ούτε τις απόψεις των υπολοίπων συναδέλφων που δούλεψαν/δουλεύουν στο Zeus ούτε της εταιρίας φυσικά. Θα έπρεπε να εννοούνται αυτά, αλλά ποιος ξέρει τι μπορεί να σκεφτεί κάποιος…

Onion Service Authorization Cookie

Tor Hidden/Onion Services include a small gem that is not so well known, there’s a way to authorize only specific clients to use an Onion Service through a cookie. It sounds a bit like .htaccess for Hidden/Onion Services.
I got asked today about how I use this authorization mechanism, so here it is:

In server’s torrc:

HiddenServiceDir /var/lib/tor/myssh
HiddenServiceAuthorizeClient basic myclient
HiddenServicePort 3221 12223

For those who want even more “anonymity”, there’s even a ‘stealth’ mode…just replace basic with stealth. Read Tor’s man page for more info on stealth mode.

Then in /var/lib/tor/myssh/hostname one will see something like:

# cat /var/lib/tor/myssh/hostname  
keesh0ahGh6lahbe.onion auliech8bu7aighaiv4aiW # client: myclient

Now on the client side just add to the client’s torrc this:
HidServAuth keesh0ahGh6lahbe.onion auliech8bu7aighaiv4aiW

That’s it…it’s extremely simple to use and can potentially protect Onion Services that are only to be used by closed groups. Anyone who doesn’t have the cookie won’t be able to connect to the onion service.

Απόφαση των ασφαλιστικών μέτρων του 2013 της ΑΕΠΙ κατά παρόχων

Πριν λίγες μέρες βγήκε η απόφαση (13478 22/12/2014) των ασφαλιστικών μέτρων που είχε καταθέσει η ΑΕΠΙ το 2013(!) κατά των παρόχων Internet στην Ελλάδα για να λογοκρίνουν/αποκλείσουν διάφορα sites, μεταξύ αυτών και του (Περισσότερα στο σχετικό link).

Το δικαστήριο απέρριψε τα ασφαλιστικά αυτά μέτρα και δικαίωσε τους παρόχους.

Το κείμενο της απόφασης είναι αρκετά μεγάλο, 49 σελίδες, και δεν είμαι νομικός για να την μελετήσω και να την κρίνω στο σύνολό της. Παρ’ όλα αυτά νομίζω πως ο τρόπος που το δικαστήριο απορρίπτει το αίτημα της ΑΕΠΙ έχει μεγάλο ενδιαφέρον:

[…] Τα αιτούμενα δε ασφαλιστικά μέτρα, ως μέτρα επιβολής και προάσπισης των παραβιαζομένων δικαιωμάτων των δικαιούχων και μελών των αιτούντων νομικών προσώπων (που αφορούν όλο και λιγότερο τους ίδιους τους δημιουργούς και περισσότερο τα συμφέροντα των ίδιων των εταιριών της πολιτιστικής βιομηχανίας), στο σύνολό τους, συνιστούν περιορισμούς των κατωτέρω αναφερομένων δικαιωμάτων, οι οποίοι, όμως, δεν είναι συμβατοί με την αρχή της αναλογικότητας και με το απαραβίαστο: (α) της ελευθερίας της πληροφόρησης (άρθρο 5 α παρ. 1 Σ), (β) του δικαιώματος συμμετοχής στην κοινωνία της πληροφορίας (άρθρο 5 α παρ. 2 Σ), ως αναγκαίας προϋπόθεσης για την ισότιμη συμμετοχή των ατόμων στην κοινωνική, πολιτική, και οικονομική ζωή καθώς και για την με ουσιαστικό τρόπο ενάσκηση των θεμελιωδών δικαιωμάτων τους, (γ) του δικαιώματος προστασίας από τη συλλογή, επεξεργασία και χρήση των προσωπικών δεδομένων (άρθρο 9 α Σ), (δ) του απορρήτου της ελεύθερης ανταπόκρισης και επικοινωνίας (άρθρο 19 Σ), δεδομένου ότι μέσω αυτών καταστέλλονται, αδιακρίτως, όχι μόνον παράνομες αλλά και νόμιμες πράξεις και ως εκ τούτου συνιστούν ανεπίτρεπτη επέμβαση στις τελευταίες, που ενώ δεν σχετίζονται με την διακίνηση έργων (προστατευόμενων και μη), καταλήγουν να υποβαθμίζονται, και δεν πληρούν (τα αιτούμενα μέτρα) τα ειδικότερα κριτήρια της αναγκαιότητας και της καταλληλότητας για την έστω και εν μέρει επίτευξη του επιδιωκόμενου ως άνω σκοπού. Αυτό καθίσταται σαφές από τη στιγμή που όπως αναφέρεται οι συγκεκριμένες, ανωτέρω παρατιθέμενες, από τις επίμαχες ιστοσελίδες, λειτουργούν ήδη με άλλη IP. Επιπλέον, τα αιτούμενα ασφαλιστικά μέτρα αντιβαίνουν στο άρθρο 16 του Χάρτη Θεμελιωδών Δικαιωμάτων της ΕΕ, παραβιάζοντας το δικαίωμα των καθ’ ων παρόχων στην επιχειρηματικότητα, αλλά και στην βασική αρχή της διαδικτυακής ουδετερότητας, που προβλέπει ότι όλες οι πληροφορίες πρέπει να διακινούνται χωρίς διάκριση, ανεξάρτητα της φύσης και του σκοπού τους από τους παρόχους σύνδεσης. Το κόστος δε που τα αιτούμενα ασφαλιστικά μέτρα συνεπάγεται για τα έννομα συμφέροντα των τελικών χρηστών και συνδρομητών των καθ’ ων, είναι δυσανάλογο με την επιδιωκόμενη (και αμφισβητούμενη) από πλευράς των μελών των αιτούντων νομικών προσώπων ωφέλεια, ενόψει του σοβαρού περιορισμού θεμελιωδών δικαιωμάτων των πρώτων και των γενικότερων συνεπειών που έχουν οι αιτούμενες ρυθμιστικές επεμβάσεις στην εξέλιξη της κοινωνίας της πληροφορίας σε συνθήκες ελευθερίας και δικαιωσύνης. […]

Νίκη λοιπόν…μέχρι την επόμενη δίκη ή τον επόμενο νόμο που θα προσπαθήσει να περάσει η ΑΕΠΙ.

Το κείμενο της απόφασης (7Mb): Απόφαση Ασφαλιστικών μέτρων ΑΕΠΙ 2013

Υ.Γ. το pdf είναι μόνο εικόνες και το έχω κάνει resize, αν υπάρχει κάποιος που μπορεί να κάνει το OCR και θέλει την αυθεντική ανάλυση ας επικοινωνήσει μαζί μου.

Anonymous edits in Hellenic Wikipedia from Hellenic Parliament IPs

Inspired from another project called “Anonymous Wikipedia edits from the Norwegian parliament and government offices” I decided to create something similar for the Hellenic Parliament.

I downloaded the XML dumps (elwiki-20140702-pages-meta-history.xml.7z) for the elwiki from The compressed file is less than 600Mb but uncompressing it leads to a 73Gb XML which contains the full history of edits. Then I modified a parser I found on this blog to extract the data I wanted: Page Title, Timestamp and IP.

Then it was easy to create a list that contains all the edits that have been created by Hellenic Parliament IPs ( throughout the History of Hellenic Wikipedia:
The list

Interesting edits

  1. Former Prime Minister “Κωνσταντίνος Σημίτης”
    An IP from inside the Hellenic Parliament tried to remove the following text at least 3 times in 17-18/02/2014. This is a link to the first edit: Diff 1.

    Για την περίοδο 1996-2001 ξοδεύτηκαν 5,2 τρις δρχ σε εξοπλισμούς. Οι δαπάνες του Β` ΕΜΠΑΕ (2001-2006) υπολογίζεται πως έφτασαν τα 6 με 7 τρις δρχ.[ ”To κόστος των εξοπλισμών”], εφημερίδα ”Ελευθεροτυπία”, δημοσίευση [[1 Αυγούστου]] [[2001]].Έπειτα απο τη σύλληψη και ενοχή του Γ.Καντά,υπάρχουν υπόνοιες για την εμπλοκή του στο σκάνδαλο με μίζες από Γερμανικές εταιρίες στα εξοπλιστικά,κάτι το οποίο διερευνάται απο την Εισαγγελία της Βρέμης.

  2. Former MP “Δημήτρης Κωνσταντάρας”
    Someone modified his biography twice. Diff Links: Diff 1 Diff 2.
  3. Former football player “Δημήτρης Σαραβάκος”
    In the following edit someone updated this player’s bio adding that he ‘currently plays in porn films’. Diff link. The same editor seems to have removed that reference later, diff link.
  4. Former MP “Θεόδωρος Ρουσόπουλος”
    Someone wanted to update this MP’s bio and remove some reference of a scandal. Diff link.
  5. The movie “Ραντεβού με μια άγνωστη”
    Claiming that the nude scenes are probably not from the actor named “Έλενα Ναθαναήλ”. Diff link.
  6. The soap opera “Χίλιες και Μία Νύχτες (σειρά)”
    Someone created the first version of the article on this soap opera. Diff Link.
  7. Politician “Γιάννης Λαγουδάκος”
    Someone edited his bio so it seemed that he would run for MP with the political party called “Ανεξάρτητοι Έλληνες”. Diff Link
  8. University professor “Γεώργιος Γαρδίκας”
    Someone edited his profile and added a link for amateur football team “Αγιαξ Αιγάλεω”. Diff Link.
  9. Politician “Λευτέρης Αυγενάκης”
    Someone wanted to fix his bio and upload a file, so he/she added a link from the local computer “C:\Documents and Settings\user2\Local Settings\Temp\ΑΥΓΕΝΑΚΗΣ”. Diff link.
  10. MP “Κώστας Μαρκόπουλος”
    Someone wanted to fix his bio regarding his return to the “Νέα Δημοκρατία” political party. Diff Link.
  11. (Golden Dawn) MP “Νίκος Μιχαλολιάκος”
    Someone was trying to “fix” his bio removing some accusations. Diff Link.
  12. (Golden Dawn) MP “Ηλίας Κασιδιάρης”
    Someone was trying to fix his bio and remove various accusations and incidents. Diff Link 1, Diff Link 2, Diff Link 3.

Who’s done the edits ?
The IP range of the Hellenic Parliament is not only used by MPs but from people working in the parliament as well. Don’t rush to any conclusions…
Oh, and the IP is probably a proxy inside the Parliament.

Threat Model
Not that it matters a lot for MPs and politicians in general, but it’s quite interesting that if someone “anonymously” edits a wikipedia article, wikimedia stores the IP of the editor and provides it to anyone that wants to download the wiki archives. If the IP range is known, or someone has the legal authority within a country to force an ISP to reveal the owner of an IP, it is quite easy to spot the actual person behind an “anonymous” edit. But if someone creates an account to edit wikipedia articles, wikimedia does not publish the IPs of its users, the account database is private. To get an IP of a user, one would need to take wikimedia to courts to force them to reveal that account’s IP address. Since every wikipedia article edit history is available for anyone to download, one is actually “more anonymous to the public” if he/she logs in or creates a (new) account every time before editing an article, than editing the same article without an account. Unless someone is afraid that wikimedia will leak/disclose their account’s IPs.
So depending on their threat model, people can choose whether they want to create (new) account(s) before editing an article or not 🙂

Similar Projects

  • Parliament WikiEdits
  • congress-edits
  • Riksdagen redigerar
  • Stortinget redigerer
  • AussieParl WikiEdits
  • anon
  • Bonus
    Anonymous edit from “Synaspismos Political Party” (ΣΥΡΙΖΑ) address range for “Δημοκρατική Αριστερά” political party article, changing it’s youth party blog link to the PASOK youth party blog link. Diff Link

    SMTP over Hidden Services with postfix

    More and more privacy experts are nowdays calling people to move away from the email service provider giants (gmail, yahoo!, microsoft, etc) and are urging people to set up their own email services, to “decentralize”. This brings up many many other issues though, and one of which is that if only a small group people use a certain email server, even if they use TLS, it’s relatively easy for someone passively monitoring (email) traffic to correlate who (from some server) is communicating with whom (from another server). Even if the connection and the content is protected by TLS and GPG respectively, some people might feel uncomfortable if a third party knew that they are actually communicating (well these people better not use email, but let’s not get carried away).

    This post is about sending SMTP traffic between two servers on the Internet over Tor, that is without someone being able to easily see who is sending what to whom. IMHO, it can be helpful in some situations to certain groups of people.

    There are numerous posts on the Internet about how you can Torify all the SMTP connections of a postfix server, the problem with this approach is that most exit nodes are blacklisted by RBLs so it’s very probable that the emails sent will either not reach their target or will get marked as spam. Another approach is to create hidden services and make users send emails to each other at their hidden service domains, eg username@a2i4gzo2bmv9as3avx.onion. This is quite uncomfortable for users and it can never get adopted.

    There is yet another approach though, the communication could happen over Tor hidden services that real domains are mapped to.

    Both sides need to run a Tor client:
    aptitude install tor torsocks

    The setup is the following, the postmaster on the receiving side sets up a Tor Hidden Service for their SMTP service (receiver). This is easily done in his server (server-A) with the following line in the torrc:
    HiddenServicePort 25 25. Let’s call this HiddenService-A (abcdefghijklmn12.onion). He then needs to notify other postmasters of this hidden service.

    The postmaster on the sending side (server-B) needs to create 2 things, a torified SMTP service (sender) for postfix and a transport map that will redirect emails sent to domains of server-A to HiddenService-A.

    Steps needed to be executed on server-B:
    1. Create /usr/lib/postfix/smtp_tor with the following content:

    torsocks /usr/lib/postfix/smtp $@

    2. Make it executable
    chmod +x /usr/lib/postfix/smtp_tor

    3. Edit /etc/postfix/ and add a new service entry
    smtptor unix - - - - - smtp_tor
    For Debian Stretch and/or for postfix 2.11+ this should be:

    smtptor      unix  -       -       -       -       -       smtp_tor
      -o smtp_dns_support_level=disabled

    4. If you don’t already have a transport map file, create /etc/postfix/transport with content (otherwise just add the following to your transport maps file):        smtptor:[abcdefghijklmn12.onion]        smtptor:[bbbcccdddeeeadas.onion]

    5. if you don’t already have a transport map file edit /etc/postfix/ and add the following:
    transport_maps = hash:/etc/postfix/transport

    6. run the following:
    postmap /etc/postfix/transport && service postfix reload

    7. If you’re running torsocks version 2 you need to set AllowInbound 1 in /etc/tor/torsocks.conf. If you’re using torsocks version 1,you shouldn’t, no changes are necessary.

    Well that’s about it, now every email sent from a user of server-B to will actually get sent over Tor to server-A on its HiddenService. Since HiddenServices are usually mapped on, it will bypass the usual sender restrictions. Depending on the setup of the receiver it might even evade spam detection software, so beware…If both postmasters follow the above steps then all emails sent from users of server-A to users of server-B and vice versa will be sent anonymously over Tor.

    There is nothing really new in this post, but I couldn’t find any other posts describing such a setup. Since it requires both sides to actually do something for things to work, I don’t think it can ever be used widely, but it’s still yet another way to take advantage of Tor and Hidden Services.

    !Open Relaying
    When you setup a tor hidden service to accept connections to your SMTP server, you need to be careful that you aren’t opening your mail server up to be an open relay on the tor network. You need to very carefully inspect your configuration to see if you are allowing connections to relay mail, and if you are, there are a couple ways to stop it.

    You can tell if you are allowing to relay mail if you have something like this in your postfix configuration by looking at the smtpd_recipient_restrictions and seeing if you have permit_mynetworks, and your mynetworks variable includes (default). The tor hidden service will connect via, so if you allow that to send without authentication, you are an open relay on the tor network, and you don’t want that…

    Three ways of dealing with this.

    1. Remove remove from mynetworks and use port 25/587 as usual.

    2. Create a new secondary transport that has a different set of restrictions. Copy the restrictions from and remove ‘permit_mynetworks’ from them

    2525      inet  n       -       -       -       -       smtpd
       -o smtpd_recipient_restrictions=XXXXXXX
       -o smtpd_sender_restrictions=YYYYYY
       -o smtpd_helo_restrictions=ZZZZ
    2587 inet n - - - - smtpd
       -o smtpd_enforce_tls=yes
       -o smtpd_tls_security_level=encrypt
       -o smtpd_sasl_auth_enable=yes
       -o smtpd_client_restrictions=permit_sasl_authenticated,reject
       -o smtpd_sender_restrictions=
       -o smtpd_recipient_restrictions=XXXXXXX
       -o smtpd_sender_restrictions=YYYYYY
       -o smtpd_helo_restrictions=XXXXX

    Then edit your /etc/tor/torrc

    HiddenServiceDir /var/lib/tor/smtp_onion
    HiddenServicePort 25 2525
    HiddenServicePort 587 2587

    3. If your server is not used by other servers to relay email, then you can use the newer postfix variable that was designed for restricting relays smtpd_relay_restrictions (remember NOT to use permit_mynetworks there) to allow emails to be “relayed” by the onion service:

    smtpd_relay_restrictions = permit_sasl_authenticated,
    smtpd_recipient_restrictions =
            check_recipient_access hash:$checks_dir/recipient_access,

    Can hidden services scale to support hundreds or thousands of connections e.g. from a mailing list ? who knows…
    This type of setup needs the help of big fishes (large independent email providers like Riseup) to protect the small fishes (your own email server). So a new problem arises, bootstrapping and I’m not really sure this problem has any elegant solution. The more servers use this setup though, the more useful it becomes against passive adversaries trying to correlate who communicates with whom.
    The above setup works better when there are more than one hidden services running on the receiving side so a passive adversary won’t really know that the incoming traffic is SMTP, eg when you also run a (busy) HTTP server as a hidden service at the same machine.
    Hey, where did MX record lookup go ?

    Trying it
    If anyone wants to try it, you can send me an email using voidgrz25evgseyc.onion as the Hidden SMTP Service (in the transport map).

    ehloonion/onionmx github repository

    *Update 01/02/2015 Added information about !Open Relaying and torsocks version 2 configuration*
    *Update 11/10/2016 Updated information about !Open Relaying*
    *Update 14/06/2018 Added link to ehloonion/onionmx*