I've followed the instructions for Using Protocol Forwarding on the Google Cloud Platform. So I now have something like this:
$ gcloud compute forwarding-rules list
NAME REGION IP_ADDRESS IP_PROTOCOL TARGET
x-fr-1 us-west1 104.198.?.?? TCP us-west1-a/targetInstances/x-target-instance
x-fr-2 us-west1 104.198.?.?? TCP us-west1-a/targetInstances/x-target-instance
x-fr-3 us-west1 104.198.??.??? TCP us-west1-a/targetInstances/x-target-instance
x-fr-4 us-west1 104.198.??.??? TCP us-west1-a/targetInstances/x-target-instance
x-fr-5 us-west1 104.198.?.??? TCP us-west1-a/targetInstances/x-target-instance
(Note: Names have been changed and question-marks have been substituted. I'm not sure it matters to keep these private but better safe than sorry.)
My instance "x" is in the "x-target-instance" and has five forwarding rules "x-fr-1" through "x-fr-5". I'm running nginx on "x" and I can access it from any of its 6 external IP addresses (1 for the instance + 5 forwarding rules). So far, so good.
I am interested now in binding a server to these external IP addresses. To explore, I tried using Python:
import socket
import time
def serve(ip_address, port=80):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((ip_address, port))
try:
sock.listen(5)
while True:
con, _ = sock.accept()
print con.getpeername(), con.getsockname()
con.send(time.ctime())
con.close()
finally:
sock.close()
Now I can bind "0.0.0.0" and I get some interesting results:
>>> serve("0.0.0.0")
('173.228.???.??', 57288) ('10.240.?.?', 80)
('173.228.???.??', 57286) ('104.198.?.??', 80)
When I communicate with the server on its external IP address, the "getsockname" method returns the instance's internal IP address. But when I communicate with the server on an external IP address as used by a forwarding rule, then the "getsockname" methods returns the external IP address.
Ok, now I bind the instance's internal IP address:
>>> serve("10.240.?.?")
('173.228.???.??', 57295) ('10.240.?.?', 80)
Again I can communicate with the server on its external IP address, and the "getsockname" method returns the instance's internal IP address. That seems a bit odd.
Also, if I try to bind the instance's external IP address:
>>> serve("104.198.?.??")
error: [Errno 99] Cannot assign requested address
Then I get an error.
But, if I try to bind the external IP addresses used by the forwarding rules and then make a request:
>>> serve("104.198.??.???")
('173.228.???.??', 57313) ('104.198.??.???', 80)
It works.
Finally I look at "ifconfig":
ens4 Link encap:Ethernet HWaddr 42:01:0a:??:??:??
inet addr:10.240.?.? Bcast:10.240.?.? Mask:255.255.255.255
inet6 addr: fe80::4001:???:????:2/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1460 Metric:1
RX packets:37554 errors:0 dropped:0 overruns:0 frame:0
TX packets:32286 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:41201244 (41.2 MB) TX bytes:3339072 (3.3 MB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:9403 errors:0 dropped:0 overruns:0 frame:0
TX packets:9403 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:3155046 (3.1 MB) TX bytes:3155046 (3.1 MB)
And I see only two interfaces. Clearly, the abilities of Google Cloud Platform Networking has exceeded what I can remember from my Computer Networking class in college. To summarize my observations:
- If I want to bind on the instance's external IP address, then I bind its internal IP address.
- A process bound to the instance's internal IP address can not differentiate the destination IP between the instance's internal or external IP addresses.
- The single networking adapter, "ens4", is receiving packets bound for any of the instance's 6 external IP address.
And here's my questions:
- Why can I not bind the instance's external IP address?
- How is it that I can bind the external IP addresses used by forwarding rules when I have no associated network adapters?
- If I want to restrict SSH access to the instance's external IP address, should I configure SSH to bind the internal IP address?
- If I setup an HTTP proxy on one of the external IP addresses used by a forwarding rule, what will be the source IP of the proxied request?
- Lastly, and this may be a bug, why is the forwarding rules list empty in the web interface at https://console.cloud.google.com/networking/loadbalancing/advanced/forwardingRules/list?project=xxx when I can see them with "gcloud compute forwarding-rules list"?