[Twisted-Python] Can transport.write() to hostname instead of IP address?
Tom Most
twm at freecog.net
Thu Aug 16 21:18:46 MDT 2018
Hi Sean,
To summarize, you are writing a client application using Twisted which
needs to talk with a service behind an Nginx reverse proxy. The reverse
proxy requires use of TLS (a.k.a. SSL) and SNI to identify the
appropriate backend service.
If you were using HTTP, Twisted's twisted.web.client.Agent[1] API
already does the right thing here -- it takes the hostname from the URL
it is given and populates SNI.
For your custom protocol on top of TLS, you should use a TLS endpoint to
connect to the server from your client. This is a little difficult to
discover because there isn't a TLS endpoint per se -- instead, there is
a function which wraps another endpoint. See the TLS section in the
endpoint documentation[2], which includes this example:
wrapped = HostnameEndpoint('example.com', 443) contextFactory =
optionsForClientTLS(hostname=u'example.com') endpoint =
wrapClientTLS(contextFactory, wrapped) conn =
endpoint.connect(Factory.forProtocol(Protocol))
I'll break this down:
1. HostnameEndpoint will resolve the hostname to an IP address and
creates a TCP connection to port 443.2. The optionsForClientTLS[3] function generates an object which
represents the TLS connection options. Importantly, it enables SNI
based on the hostname passed to it.3. wrapClientTLS[4] returns an endpoint which layers TLS on top of the
plain TCP connection generated by HostnameEndpoint. It also takes the
TLS options as an argument.4. conn is a Deferred which will fire with a protocol instance generated
by the factory passed to connect().
This is basically what Agent does internally, as I understand it.
Hope this helps,
Tom
On Thu, Aug 16, 2018, at 6:44 PM, Sean DiZazzo wrote:
> I guess thats still kind of confusing without making something more
> clear...>
> In my example, both myprotocol.example.com and test.example.com DNS
> records would point to the same IP address. One nginx instance then
> listens on that IP and serves up several ssl apps. They go through a
> "mapper" that uses the SNI and the ssl_preread directive to read the
> destination hostname of the packet to determine which app to route the
> traffic to.>
> I just want transport.write() to not resolve the ip address of the
> host I pass in. Everything will work if it connects and sends packets
> to myprotocol.example.com:443[5] instead of 23.23.23.23:443.>
> Nginx reference:
> http://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html
>
> On Thu, Aug 16, 2018 at 6:14 PM, Sean DiZazzo
> <sean.dizazzo at gmail.com> wrote:>> Thanks for responding, Adi!
>>
>> I don't want each packet to go it's own way from Twisted. They all
>> go to the same place from each instance of the server/protocol. They
>> go to my custom protocol listening on another local port.>>
>> It's just that I'm serving up several different ssl apps on the same
>> nginx server, and nginx uses the hostname to route the packets. So
>> in this case, traffic coming in on http.example.com:443 might be
>> routed to an https app listening on a socket, and traffic coming in
>> to myprotocol.example.com:443 should be routed to my own protocol
>> listening on port 9999. So if nginx doesn't get the hostname, it
>> doesn't know to route the packet to my custom protocol instead of the
>> web server. Does that make sense?>>
>> It seems that the transport is resolving the hostname to an ip
>> address and then sending the traffic to the generic ip which is not
>> enough info for nginx to route the packet correctly.>>
>> On Thu, Aug 16, 2018 at 5:49 PM, Adi Roiban <adi at roiban.ro> wrote:
>>> On Fri, 17 Aug 2018 at 01:25, Sean DiZazzo <sean.dizazzo at gmail.com>
>>> wrote:
>>> >
>>> > Hi all!
>>> >
>>> > After I start a reactor connecting to a specific hostname and
>>> > port, I do my thing and then call transport.write() to send the
>>> > data to the peer.
>>> >
>>> > From what I can tell, though, the hostname is resolved, and the
>>> > data is written back to the ip address itself, instead of the
>>> > hostname I started the reactor with.
>>> >
>>> > This is a problem in my case because we are using nginx's
>>> > ssl_preread server_name directive to route several different
>>> > streams all coming in on the same ip address.
>>> >
>>> > So the write() method needs to explicitly use the hostname to
>>> > route the packet properly.
>>> >
>>> > So... Is there any way to have transport.write() use the hostname
>>> > given instead of it's resolved IP address? Or am I missing
>>> > something?
>>> >
>>>
>>> I assume you are using TCP here.>>>
>>> I guess that you are missing something.
>>>
>>> If you want each write to go over its own way / route and have the>>> hostname re-resolved you should open + write + close a
>>> connection for>>> each write.
>>>
>>> But I think that there is something else there and this is now what
>>> you want :)>>> Do you use HTTP or have a custom protocol?
>>>
>>> Cheers,
>>>
>>> Adi Roiban
>>>
>>> _______________________________________________
>>> Twisted-Python mailing list
>>> Twisted-Python at twistedmatrix.com
>>> https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
> _________________________________________________
> Twisted-Python mailing list
> Twisted-Python at twistedmatrix.com
> https://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
Links:
1. https://twistedmatrix.com/documents/current/api/twisted.web.client.Agent.html
2. https://twistedmatrix.com/documents/current/core/howto/endpoints.html#endpoint-types-included-with-twisted
3. https://twistedmatrix.com/documents/18.7.0/api/twisted.internet.ssl.optionsForClientTLS.html
4. https://twistedmatrix.com/documents/current/api/twisted.internet.endpoints.html#wrapClientTLS
5. http://myprotocol.example.com:443/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: </pipermail/twisted-python/attachments/20180816/7159fed4/attachment-0002.html>
More information about the Twisted-Python
mailing list