1'''
2'''
3#  Licensed to the Apache Software Foundation (ASF) under one
4#  or more contributor license agreements.  See the NOTICE file
5#  distributed with this work for additional information
6#  regarding copyright ownership.  The ASF licenses this file
7#  to you under the Apache License, Version 2.0 (the
8#  "License"); you may not use this file except in compliance
9#  with the License.  You may obtain a copy of the License at
10#
11#      http://www.apache.org/licenses/LICENSE-2.0
12#
13#  Unless required by applicable law or agreed to in writing, software
14#  distributed under the License is distributed on an "AS IS" BASIS,
15#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16#  See the License for the specific language governing permissions and
17#  limitations under the License.
18
19Test.Summary = '''
20Test tunneling based on SNI
21'''
22
23# Define default ATS
24ts = Test.MakeATSProcess("ts", command="traffic_manager", select_ports=True, enable_tls=True)
25server_foo = Test.MakeOriginServer("server_foo", ssl=True)
26server_bar = Test.MakeOriginServer("server_bar", ssl=True)
27server2 = Test.MakeOriginServer("server2")
28#dns = Test.MakeDNServer("dns", default=['127.0.0.1'])
29dns = Test.MakeDNServer("dns")
30
31request_foo_header = {"headers": "GET / HTTP/1.1\r\nHost: foo.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
32request_bar_header = {"headers": "GET / HTTP/1.1\r\nHost: bar.com\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
33response_foo_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": "foo ok"}
34response_bar_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": "bar ok"}
35server_foo.addResponse("sessionlog.json", request_foo_header, response_foo_header)
36server_bar.addResponse("sessionlog.json", request_bar_header, response_bar_header)
37
38# add ssl materials like key, certificates for the server
39ts.addSSLfile("ssl/signed-foo.pem")
40ts.addSSLfile("ssl/signed-foo.key")
41ts.addSSLfile("ssl/signed-bar.pem")
42ts.addSSLfile("ssl/signed-bar.key")
43ts.addSSLfile("ssl/server.pem")
44ts.addSSLfile("ssl/server.key")
45ts.addSSLfile("ssl/signer.pem")
46ts.addSSLfile("ssl/signer.key")
47
48dns.addRecords(records={"localhost": ["127.0.0.1"]})
49dns.addRecords(records={"one.testmatch": ["127.0.0.1"]})
50dns.addRecords(records={"two.example.one": ["127.0.0.1"]})
51# Need no remap rules.  Everything should be processed by sni
52
53# Make sure the TS server certs are different from the origin certs
54ts.Disk.ssl_multicert_config.AddLine(
55    'dest_ip=* ssl_cert_name=signed-foo.pem ssl_key_name=signed-foo.key'
56)
57
58# Case 1, global config policy=permissive properties=signature
59#         override for foo.com policy=enforced properties=all
60ts.Disk.records_config.update({
61    'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
62    'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
63    'proxy.config.http.connect_ports': '{0} {1} {2}'.format(ts.Variables.ssl_port, server_foo.Variables.SSL_Port, server_bar.Variables.SSL_Port),
64    'proxy.config.ssl.server.cipher_suite': 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:RC4-MD5:AES128-SHA:AES256-SHA:DES-CBC3-SHA!SRP:!DSS:!PSK:!aNULL:!eNULL:!SSLv2',
65    'proxy.config.ssl.client.CA.cert.path': '{0}'.format(ts.Variables.SSLDir),
66    'proxy.config.ssl.client.CA.cert.filename': 'signer.pem',
67    'proxy.config.exec_thread.autoconfig.scale': 1.0,
68    'proxy.config.url_remap.pristine_host_hdr': 1,
69    'proxy.config.dns.nameservers': '127.0.0.1:{0}'.format(dns.Variables.Port),
70    'proxy.config.dns.resolv_conf': 'NULL'
71})
72
73# foo.com should not terminate.  Just tunnel to server_foo
74# bar.com should terminate.  Forward its tcp stream to server_bar
75# empty SNI should tunnel to server_bar
76ts.Disk.sni_yaml.AddLines([
77    'sni:',
78    '- fqdn: foo.com',
79    "  tunnel_route: localhost:{0}".format(server_foo.Variables.SSL_Port),
80    "- fqdn: bob.*.com",
81    "  tunnel_route: localhost:{0}".format(server_foo.Variables.SSL_Port),
82    "- fqdn: '*.match.com'",
83    "  tunnel_route: $1.testmatch:{0}".format(server_foo.Variables.SSL_Port),
84    "- fqdn: '*.ok.*.com'",
85    "  tunnel_route: $2.example.$1:{0}".format(server_foo.Variables.SSL_Port),
86    "- fqdn: ''",  # No SNI sent
87    "  tunnel_route: localhost:{0}".format(server_bar.Variables.SSL_Port)
88])
89
90tr = Test.AddTestRun("foo.com Tunnel-test")
91tr.Processes.Default.Command = "curl -v --resolve 'foo.com:{0}:127.0.0.1' -k  https://foo.com:{0}".format(ts.Variables.ssl_port)
92tr.ReturnCode = 0
93tr.Processes.Default.StartBefore(server_foo)
94tr.Processes.Default.StartBefore(server_bar)
95tr.Processes.Default.StartBefore(dns)
96tr.Processes.Default.StartBefore(Test.Processes.ts)
97tr.StillRunningAfter = ts
98tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Could Not Connect", "Curl attempt should have succeeded")
99tr.Processes.Default.Streams.All += Testers.ExcludesExpression(
100    "Not Found on Accelerato", "Should not try to remap on Traffic Server")
101tr.Processes.Default.Streams.All += Testers.ExcludesExpression("CN=foo.com", "Should not TLS terminate on Traffic Server")
102tr.Processes.Default.Streams.All += Testers.ContainsExpression("HTTP/1.1 200 OK", "Should get a successful response")
103tr.Processes.Default.Streams.All += Testers.ExcludesExpression("ATS", "Do not terminate on Traffic Server")
104tr.Processes.Default.Streams.All += Testers.ContainsExpression("foo ok", "Should get a response from bar")
105
106tr = Test.AddTestRun("bob.bar.com Tunnel-test")
107tr.Processes.Default.Command = "curl -v --resolve 'bob.bar.com:{0}:127.0.0.1' -k  https://bob.bar.com:{0}".format(
108    ts.Variables.ssl_port)
109tr.ReturnCode = 0
110tr.StillRunningAfter = ts
111tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Could Not Connect", "Curl attempt should have succeeded")
112tr.Processes.Default.Streams.All += Testers.ExcludesExpression(
113    "Not Found on Accelerato", "Should not try to remap on Traffic Server")
114tr.Processes.Default.Streams.All += Testers.ExcludesExpression("CN=foo.com", "Should not TLS terminate on Traffic Server")
115tr.Processes.Default.Streams.All += Testers.ContainsExpression("HTTP/1.1 200 OK", "Should get a successful response")
116tr.Processes.Default.Streams.All += Testers.ExcludesExpression("ATS", "Do not terminate on Traffic Server")
117tr.Processes.Default.Streams.All += Testers.ContainsExpression("foo ok", "Should get a response from bar")
118
119tr = Test.AddTestRun("bar.com no Tunnel-test")
120tr.Processes.Default.Command = "curl -v --resolve 'bar.com:{0}:127.0.0.1' -k  https://bar.com:{0}".format(ts.Variables.ssl_port)
121tr.ReturnCode = 0
122tr.StillRunningAfter = ts
123tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Could Not Connect", "Curl attempt should have succeeded")
124tr.Processes.Default.Streams.All += Testers.ContainsExpression("Not Found on Accelerato", "Terminates on on Traffic Server")
125tr.Processes.Default.Streams.All += Testers.ContainsExpression("ATS", "Terminate on Traffic Server")
126
127tr = Test.AddTestRun("no SNI Tunnel-test")
128tr.Processes.Default.Command = "curl -v -k  https://127.0.0.1:{0}".format(ts.Variables.ssl_port)
129tr.ReturnCode = 0
130tr.StillRunningAfter = ts
131tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Could Not Connect", "Curl attempt should have succeeded")
132tr.Processes.Default.Streams.All += Testers.ExcludesExpression(
133    "Not Found on Accelerato", "Should not try to remap on Traffic Server")
134tr.Processes.Default.Streams.All += Testers.ContainsExpression("HTTP/1.1 200 OK", "Should get a successful response")
135tr.Processes.Default.Streams.All += Testers.ExcludesExpression("ATS", "Do not terminate on Traffic Server")
136tr.Processes.Default.Streams.All += Testers.ContainsExpression("bar ok", "Should get a response from bar")
137
138
139tr = Test.AddTestRun("one.match.com Tunnel-test")
140tr.Processes.Default.Command = "curl -vvv --resolve 'one.match.com:{0}:127.0.0.1' -k  https://one.match.com:{0}".format(
141    ts.Variables.ssl_port)
142tr.ReturnCode = 0
143tr.StillRunningAfter = ts
144tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Could Not Connect", "Curl attempt should have succeeded")
145tr.Processes.Default.Streams.All += Testers.ExcludesExpression(
146    "Not Found on Accelerato", "Should not try to remap on Traffic Server")
147tr.Processes.Default.Streams.All += Testers.ExcludesExpression("CN=foo.com", "Should not TLS terminate on Traffic Server")
148tr.Processes.Default.Streams.All += Testers.ContainsExpression("HTTP/1.1 200 OK", "Should get a successful response")
149tr.Processes.Default.Streams.All += Testers.ExcludesExpression("ATS", "Do not terminate on Traffic Server")
150tr.Processes.Default.Streams.All += Testers.ContainsExpression("foo ok", "Should get a response from tm")
151
152
153tr = Test.AddTestRun("one.ok.two.com Tunnel-test")
154tr.Processes.Default.Command = "curl -vvv --resolve 'one.ok.two.com:{0}:127.0.0.1' -k  https:/one.ok.two.com:{0}".format(
155    ts.Variables.ssl_port)
156tr.ReturnCode = 0
157tr.StillRunningAfter = ts
158tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Could Not Connect", "Curl attempt should have succeeded")
159tr.Processes.Default.Streams.All += Testers.ExcludesExpression(
160    "Not Found on Accelerato", "Should not try to remap on Traffic Server")
161tr.Processes.Default.Streams.All += Testers.ExcludesExpression("CN=foo.com", "Should not TLS terminate on Traffic Server")
162tr.Processes.Default.Streams.All += Testers.ContainsExpression("HTTP/1.1 200 OK", "Should get a successful response")
163tr.Processes.Default.Streams.All += Testers.ExcludesExpression("ATS", "Do not terminate on Traffic Server")
164tr.Processes.Default.Streams.All += Testers.ContainsExpression("foo ok", "Should get a response from tm")
165
166
167# Update sni file and reload
168tr = Test.AddTestRun("Update config files")
169# Update the SNI config
170snipath = ts.Disk.sni_yaml.AbsPath
171recordspath = ts.Disk.records_config.AbsPath
172tr.Disk.File(snipath, id="sni_yaml", typename="ats:config"),
173tr.Disk.sni_yaml.AddLines([
174    'sni:',
175    '- fqdn: bar.com',
176    '  tunnel_route: localhost:{0}'.format(server_bar.Variables.SSL_Port),
177])
178tr.StillRunningAfter = ts
179tr.StillRunningAfter = server_foo
180tr.StillRunningAfter = server_bar
181tr.Processes.Default.Env = ts.Env
182tr.Processes.Default.Command = 'echo Updated configs'
183tr.Processes.Default.ReturnCode = 0
184
185trreload = Test.AddTestRun("Reload config")
186trreload.StillRunningAfter = ts
187trreload.StillRunningAfter = server_foo
188trreload.StillRunningAfter = server_bar
189trreload.Processes.Default.Command = 'traffic_ctl config reload'
190# Need to copy over the environment so traffic_ctl knows where to find the unix domain socket
191trreload.Processes.Default.Env = ts.Env
192trreload.Processes.Default.ReturnCode = 0
193
194# Should termimate on traffic_server (not tunnel)
195tr = Test.AddTestRun("foo.com no Tunnel-test")
196tr.StillRunningAfter = ts
197# Wait for the reload to complete by running the sni_reload_done test
198tr.Processes.Default.StartBefore(server2, ready=When.FileContains(ts.Disk.diags_log.Name, 'sni.yaml finished loading', 2))
199tr.Processes.Default.Command = "curl -v --resolve 'foo.com:{0}:127.0.0.1' -k  https://foo.com:{0}".format(ts.Variables.ssl_port)
200tr.Processes.Default.Streams.All += Testers.ContainsExpression("Not Found on Accelerato", "Terminates on on Traffic Server")
201tr.Processes.Default.Streams.All += Testers.ContainsExpression("ATS", "Terminate on Traffic Server")
202tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Could Not Connect", "Curl attempt should have succeeded")
203tr.TimeOut = 30
204
205# Should tunnel to server_bar
206tr = Test.AddTestRun("bar.com  Tunnel-test")
207tr.Processes.Default.Command = "curl -v --resolve 'bar.com:{0}:127.0.0.1' -k  https://bar.com:{0}".format(ts.Variables.ssl_port)
208tr.ReturnCode = 0
209tr.StillRunningAfter = ts
210tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Could Not Connect", "Curl attempt should have succeeded")
211tr.Processes.Default.Streams.All += Testers.ExcludesExpression("Not Found on Accelerato", "Terminates on on Traffic Server")
212tr.Processes.Default.Streams.All += Testers.ExcludesExpression("ATS", "Terminate on Traffic Server")
213tr.Processes.Default.Streams.All += Testers.ContainsExpression("bar ok", "Should get a response from bar")
214