• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004 Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <string>
29 
30 #include "talk/base/gunit.h"
31 #include "talk/base/helpers.h"
32 #include "talk/base/logging.h"
33 #include "talk/base/physicalsocketserver.h"
34 #include "talk/base/socketaddress.h"
35 #include "talk/base/testclient.h"
36 #include "talk/base/thread.h"
37 #include "talk/p2p/base/relayserver.h"
38 
39 using talk_base::SocketAddress;
40 using namespace cricket;
41 
42 static const uint32 LIFETIME = 4;  // seconds
43 static const SocketAddress server_int_addr("127.0.0.1", 5000);
44 static const SocketAddress server_ext_addr("127.0.0.1", 5001);
45 static const SocketAddress client1_addr("127.0.0.1", 6000 + (rand() % 1000));
46 static const SocketAddress client2_addr("127.0.0.1", 7000 + (rand() % 1000));
47 static const char* bad = "this is a completely nonsensical message whose only "
48                          "purpose is to make the parser go 'ack'.  it doesn't "
49                          "look anything like a normal stun message";
50 static const char* msg1 = "spamspamspamspamspamspamspambakedbeansspam";
51 static const char* msg2 = "Lobster Thermidor a Crevette with a mornay sauce...";
52 
53 class RelayServerTest : public testing::Test {
54  public:
SetUpTestCase()55   static void SetUpTestCase() {
56     talk_base::InitRandom(NULL, 0);
57   }
RelayServerTest()58   RelayServerTest()
59       : main_(talk_base::Thread::Current()), ss_(main_->socketserver()),
60         username_(talk_base::CreateRandomString(12)),
61         password_(talk_base::CreateRandomString(12)) {
62   }
63  protected:
SetUp()64   virtual void SetUp() {
65     server_.reset(new RelayServer(main_));
66 
67     server_->AddInternalSocket(
68         talk_base::AsyncUDPSocket::Create(ss_, server_int_addr));
69     server_->AddExternalSocket(
70         talk_base::AsyncUDPSocket::Create(ss_, server_ext_addr));
71 
72     client1_.reset(new talk_base::TestClient(
73         talk_base::AsyncUDPSocket::Create(ss_, client1_addr)));
74     client2_.reset(new talk_base::TestClient(
75         talk_base::AsyncUDPSocket::Create(ss_, client2_addr)));
76   }
77 
Allocate()78   void Allocate() {
79     talk_base::scoped_ptr<StunMessage> req(
80         CreateStunMessage(STUN_ALLOCATE_REQUEST));
81     AddUsernameAttr(req.get(), username_);
82     AddLifetimeAttr(req.get(), LIFETIME);
83     Send1(req.get());
84     delete Receive1();
85   }
Bind()86   void Bind() {
87     talk_base::scoped_ptr<StunMessage> req(
88         CreateStunMessage(STUN_BINDING_REQUEST));
89     AddUsernameAttr(req.get(), username_);
90     Send2(req.get());
91     delete Receive1();
92   }
93 
Send1(const StunMessage * msg)94   void Send1(const StunMessage* msg) {
95     talk_base::ByteBuffer buf;
96     msg->Write(&buf);
97     SendRaw1(buf.Data(), static_cast<int>(buf.Length()));
98   }
Send2(const StunMessage * msg)99   void Send2(const StunMessage* msg) {
100     talk_base::ByteBuffer buf;
101     msg->Write(&buf);
102     SendRaw2(buf.Data(), static_cast<int>(buf.Length()));
103   }
SendRaw1(const char * data,int len)104   void SendRaw1(const char* data, int len) {
105     return Send(client1_.get(), data, len, server_int_addr);
106   }
SendRaw2(const char * data,int len)107   void SendRaw2(const char* data, int len) {
108     return Send(client2_.get(), data, len, server_ext_addr);
109   }
Send(talk_base::TestClient * client,const char * data,int len,const SocketAddress & addr)110   void Send(talk_base::TestClient* client, const char* data,
111             int len, const SocketAddress& addr) {
112     client->SendTo(data, len, addr);
113   }
114 
Receive1()115   StunMessage* Receive1() {
116     return Receive(client1_.get());
117   }
Receive2()118   StunMessage* Receive2() {
119     return Receive(client2_.get());
120   }
ReceiveRaw1()121   std::string ReceiveRaw1() {
122     return ReceiveRaw(client1_.get());
123   }
ReceiveRaw2()124   std::string ReceiveRaw2() {
125     return ReceiveRaw(client2_.get());
126   }
Receive(talk_base::TestClient * client)127   StunMessage* Receive(talk_base::TestClient* client) {
128     StunMessage* msg = NULL;
129     talk_base::TestClient::Packet* packet = client->NextPacket();
130     if (packet) {
131       talk_base::ByteBuffer buf(packet->buf, packet->size);
132       msg = new RelayMessage();
133       msg->Read(&buf);
134       delete packet;
135     }
136     return msg;
137   }
ReceiveRaw(talk_base::TestClient * client)138   std::string ReceiveRaw(talk_base::TestClient* client) {
139     std::string raw;
140     talk_base::TestClient::Packet* packet = client->NextPacket();
141     if (packet) {
142       raw = std::string(packet->buf, packet->size);
143       delete packet;
144     }
145     return raw;
146   }
147 
CreateStunMessage(int type)148   static StunMessage* CreateStunMessage(int type) {
149     StunMessage* msg = new RelayMessage();
150     msg->SetType(type);
151     msg->SetTransactionID(
152         talk_base::CreateRandomString(kStunTransactionIdLength));
153     return msg;
154   }
AddMagicCookieAttr(StunMessage * msg)155   static void AddMagicCookieAttr(StunMessage* msg) {
156     StunByteStringAttribute* attr =
157         StunAttribute::CreateByteString(STUN_ATTR_MAGIC_COOKIE);
158     attr->CopyBytes(TURN_MAGIC_COOKIE_VALUE, sizeof(TURN_MAGIC_COOKIE_VALUE));
159     msg->AddAttribute(attr);
160   }
AddUsernameAttr(StunMessage * msg,const std::string & val)161   static void AddUsernameAttr(StunMessage* msg, const std::string& val) {
162     StunByteStringAttribute* attr =
163         StunAttribute::CreateByteString(STUN_ATTR_USERNAME);
164     attr->CopyBytes(val.c_str(), val.size());
165     msg->AddAttribute(attr);
166   }
AddLifetimeAttr(StunMessage * msg,int val)167   static void AddLifetimeAttr(StunMessage* msg, int val) {
168     StunUInt32Attribute* attr =
169         StunAttribute::CreateUInt32(STUN_ATTR_LIFETIME);
170     attr->SetValue(val);
171     msg->AddAttribute(attr);
172   }
AddDestinationAttr(StunMessage * msg,const SocketAddress & addr)173   static void AddDestinationAttr(StunMessage* msg, const SocketAddress& addr) {
174     StunAddressAttribute* attr =
175         StunAttribute::CreateAddress(STUN_ATTR_DESTINATION_ADDRESS);
176     attr->SetIP(addr.ipaddr());
177     attr->SetPort(addr.port());
178     msg->AddAttribute(attr);
179   }
180 
181   talk_base::Thread* main_;
182   talk_base::SocketServer* ss_;
183   talk_base::scoped_ptr<RelayServer> server_;
184   talk_base::scoped_ptr<talk_base::TestClient> client1_;
185   talk_base::scoped_ptr<talk_base::TestClient> client2_;
186   std::string username_;
187   std::string password_;
188 };
189 
190 // Send a complete nonsense message and verify that it is eaten.
TEST_F(RelayServerTest,TestBadRequest)191 TEST_F(RelayServerTest, TestBadRequest) {
192   talk_base::scoped_ptr<StunMessage> res;
193 
194   SendRaw1(bad, static_cast<int>(std::strlen(bad)));
195   res.reset(Receive1());
196 
197   ASSERT_TRUE(!res);
198 }
199 
200 // Send an allocate request without a username and verify it is rejected.
TEST_F(RelayServerTest,TestAllocateNoUsername)201 TEST_F(RelayServerTest, TestAllocateNoUsername) {
202   talk_base::scoped_ptr<StunMessage> req(
203       CreateStunMessage(STUN_ALLOCATE_REQUEST)), res;
204 
205   Send1(req.get());
206   res.reset(Receive1());
207 
208   ASSERT_TRUE(res);
209   EXPECT_EQ(STUN_ALLOCATE_ERROR_RESPONSE, res->type());
210   EXPECT_EQ(req->transaction_id(), res->transaction_id());
211 
212   const StunErrorCodeAttribute* err = res->GetErrorCode();
213   ASSERT_TRUE(err != NULL);
214   EXPECT_EQ(4, err->eclass());
215   EXPECT_EQ(32, err->number());
216   EXPECT_EQ("Missing Username", err->reason());
217 }
218 
219 // Send a binding request and verify that it is rejected.
TEST_F(RelayServerTest,TestBindingRequest)220 TEST_F(RelayServerTest, TestBindingRequest) {
221   talk_base::scoped_ptr<StunMessage> req(
222       CreateStunMessage(STUN_BINDING_REQUEST)), res;
223   AddUsernameAttr(req.get(), username_);
224 
225   Send1(req.get());
226   res.reset(Receive1());
227 
228   ASSERT_TRUE(res);
229   EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, res->type());
230   EXPECT_EQ(req->transaction_id(), res->transaction_id());
231 
232   const StunErrorCodeAttribute* err = res->GetErrorCode();
233   ASSERT_TRUE(err != NULL);
234   EXPECT_EQ(6, err->eclass());
235   EXPECT_EQ(0, err->number());
236   EXPECT_EQ("Operation Not Supported", err->reason());
237 }
238 
239 // Send an allocate request and verify that it is accepted.
TEST_F(RelayServerTest,TestAllocate)240 TEST_F(RelayServerTest, TestAllocate) {
241   talk_base::scoped_ptr<StunMessage> req(
242       CreateStunMessage(STUN_ALLOCATE_REQUEST)), res;
243   AddUsernameAttr(req.get(), username_);
244   AddLifetimeAttr(req.get(), LIFETIME);
245 
246   Send1(req.get());
247   res.reset(Receive1());
248 
249   ASSERT_TRUE(res);
250   EXPECT_EQ(STUN_ALLOCATE_RESPONSE, res->type());
251   EXPECT_EQ(req->transaction_id(), res->transaction_id());
252 
253   const StunAddressAttribute* mapped_addr =
254       res->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
255   ASSERT_TRUE(mapped_addr != NULL);
256   EXPECT_EQ(1, mapped_addr->family());
257   EXPECT_EQ(server_ext_addr.port(), mapped_addr->port());
258   EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr());
259 
260   const StunUInt32Attribute* res_lifetime_attr =
261       res->GetUInt32(STUN_ATTR_LIFETIME);
262   ASSERT_TRUE(res_lifetime_attr != NULL);
263   EXPECT_EQ(LIFETIME, res_lifetime_attr->value());
264 }
265 
266 // Send a second allocate request and verify that it is also accepted, though
267 // the lifetime should be ignored.
TEST_F(RelayServerTest,TestReallocate)268 TEST_F(RelayServerTest, TestReallocate) {
269   Allocate();
270 
271   talk_base::scoped_ptr<StunMessage> req(
272       CreateStunMessage(STUN_ALLOCATE_REQUEST)), res;
273   AddMagicCookieAttr(req.get());
274   AddUsernameAttr(req.get(), username_);
275 
276   Send1(req.get());
277   res.reset(Receive1());
278 
279   ASSERT_TRUE(res);
280   EXPECT_EQ(STUN_ALLOCATE_RESPONSE, res->type());
281   EXPECT_EQ(req->transaction_id(), res->transaction_id());
282 
283   const StunAddressAttribute* mapped_addr =
284       res->GetAddress(STUN_ATTR_MAPPED_ADDRESS);
285   ASSERT_TRUE(mapped_addr != NULL);
286   EXPECT_EQ(1, mapped_addr->family());
287   EXPECT_EQ(server_ext_addr.port(), mapped_addr->port());
288   EXPECT_EQ(server_ext_addr.ipaddr(), mapped_addr->ipaddr());
289 
290   const StunUInt32Attribute* lifetime_attr =
291       res->GetUInt32(STUN_ATTR_LIFETIME);
292   ASSERT_TRUE(lifetime_attr != NULL);
293   EXPECT_EQ(LIFETIME, lifetime_attr->value());
294 }
295 
296 // Send a request from another client and see that it arrives at the first
297 // client in the binding.
TEST_F(RelayServerTest,TestRemoteBind)298 TEST_F(RelayServerTest, TestRemoteBind) {
299   Allocate();
300 
301   talk_base::scoped_ptr<StunMessage> req(
302       CreateStunMessage(STUN_BINDING_REQUEST)), res;
303   AddUsernameAttr(req.get(), username_);
304 
305   Send2(req.get());
306   res.reset(Receive1());
307 
308   ASSERT_TRUE(res);
309   EXPECT_EQ(STUN_DATA_INDICATION, res->type());
310 
311   const StunByteStringAttribute* recv_data =
312       res->GetByteString(STUN_ATTR_DATA);
313   ASSERT_TRUE(recv_data != NULL);
314 
315   talk_base::ByteBuffer buf(recv_data->bytes(), recv_data->length());
316   talk_base::scoped_ptr<StunMessage> res2(new StunMessage());
317   EXPECT_TRUE(res2->Read(&buf));
318   EXPECT_EQ(STUN_BINDING_REQUEST, res2->type());
319   EXPECT_EQ(req->transaction_id(), res2->transaction_id());
320 
321   const StunAddressAttribute* src_addr =
322       res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
323   ASSERT_TRUE(src_addr != NULL);
324   EXPECT_EQ(1, src_addr->family());
325   EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr());
326   EXPECT_EQ(client2_addr.port(), src_addr->port());
327 
328   EXPECT_TRUE(Receive2() == NULL);
329 }
330 
331 // Send a complete nonsense message to the established connection and verify
332 // that it is dropped by the server.
TEST_F(RelayServerTest,TestRemoteBadRequest)333 TEST_F(RelayServerTest, TestRemoteBadRequest) {
334   Allocate();
335   Bind();
336 
337   SendRaw1(bad, static_cast<int>(std::strlen(bad)));
338   EXPECT_TRUE(Receive1() == NULL);
339   EXPECT_TRUE(Receive2() == NULL);
340 }
341 
342 // Send a send request without a username and verify it is rejected.
TEST_F(RelayServerTest,TestSendRequestMissingUsername)343 TEST_F(RelayServerTest, TestSendRequestMissingUsername) {
344   Allocate();
345   Bind();
346 
347   talk_base::scoped_ptr<StunMessage> req(
348       CreateStunMessage(STUN_SEND_REQUEST)), res;
349   AddMagicCookieAttr(req.get());
350 
351   Send1(req.get());
352   res.reset(Receive1());
353 
354   ASSERT_TRUE(res);
355   EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
356   EXPECT_EQ(req->transaction_id(), res->transaction_id());
357 
358   const StunErrorCodeAttribute* err = res->GetErrorCode();
359   ASSERT_TRUE(err != NULL);
360   EXPECT_EQ(4, err->eclass());
361   EXPECT_EQ(32, err->number());
362   EXPECT_EQ("Missing Username", err->reason());
363 }
364 
365 // Send a send request with the wrong username and verify it is rejected.
TEST_F(RelayServerTest,TestSendRequestBadUsername)366 TEST_F(RelayServerTest, TestSendRequestBadUsername) {
367   Allocate();
368   Bind();
369 
370   talk_base::scoped_ptr<StunMessage> req(
371       CreateStunMessage(STUN_SEND_REQUEST)), res;
372   AddMagicCookieAttr(req.get());
373   AddUsernameAttr(req.get(), "foobarbizbaz");
374 
375   Send1(req.get());
376   res.reset(Receive1());
377 
378   ASSERT_TRUE(res);
379   EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
380   EXPECT_EQ(req->transaction_id(), res->transaction_id());
381 
382   const StunErrorCodeAttribute* err = res->GetErrorCode();
383   ASSERT_TRUE(err != NULL);
384   EXPECT_EQ(4, err->eclass());
385   EXPECT_EQ(30, err->number());
386   EXPECT_EQ("Stale Credentials", err->reason());
387 }
388 
389 // Send a send request without a destination address and verify that it is
390 // rejected.
TEST_F(RelayServerTest,TestSendRequestNoDestinationAddress)391 TEST_F(RelayServerTest, TestSendRequestNoDestinationAddress) {
392   Allocate();
393   Bind();
394 
395   talk_base::scoped_ptr<StunMessage> req(
396       CreateStunMessage(STUN_SEND_REQUEST)), res;
397   AddMagicCookieAttr(req.get());
398   AddUsernameAttr(req.get(), username_);
399 
400   Send1(req.get());
401   res.reset(Receive1());
402 
403   ASSERT_TRUE(res);
404   EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
405   EXPECT_EQ(req->transaction_id(), res->transaction_id());
406 
407   const StunErrorCodeAttribute* err = res->GetErrorCode();
408   ASSERT_TRUE(err != NULL);
409   EXPECT_EQ(4, err->eclass());
410   EXPECT_EQ(0, err->number());
411   EXPECT_EQ("Bad Request", err->reason());
412 }
413 
414 // Send a send request without data and verify that it is rejected.
TEST_F(RelayServerTest,TestSendRequestNoData)415 TEST_F(RelayServerTest, TestSendRequestNoData) {
416   Allocate();
417   Bind();
418 
419   talk_base::scoped_ptr<StunMessage> req(
420       CreateStunMessage(STUN_SEND_REQUEST)), res;
421   AddMagicCookieAttr(req.get());
422   AddUsernameAttr(req.get(), username_);
423   AddDestinationAttr(req.get(), client2_addr);
424 
425   Send1(req.get());
426   res.reset(Receive1());
427 
428   ASSERT_TRUE(res);
429   EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
430   EXPECT_EQ(req->transaction_id(), res->transaction_id());
431 
432   const StunErrorCodeAttribute* err = res->GetErrorCode();
433   ASSERT_TRUE(err != NULL);
434   EXPECT_EQ(4, err->eclass());
435   EXPECT_EQ(00, err->number());
436   EXPECT_EQ("Bad Request", err->reason());
437 }
438 
439 // Send a binding request after an allocate and verify that it is rejected.
TEST_F(RelayServerTest,TestSendRequestWrongType)440 TEST_F(RelayServerTest, TestSendRequestWrongType) {
441   Allocate();
442   Bind();
443 
444   talk_base::scoped_ptr<StunMessage> req(
445       CreateStunMessage(STUN_BINDING_REQUEST)), res;
446   AddMagicCookieAttr(req.get());
447   AddUsernameAttr(req.get(), username_);
448 
449   Send1(req.get());
450   res.reset(Receive1());
451 
452   ASSERT_TRUE(res);
453   EXPECT_EQ(STUN_BINDING_ERROR_RESPONSE, res->type());
454   EXPECT_EQ(req->transaction_id(), res->transaction_id());
455 
456   const StunErrorCodeAttribute* err = res->GetErrorCode();
457   ASSERT_TRUE(err != NULL);
458   EXPECT_EQ(6, err->eclass());
459   EXPECT_EQ(0, err->number());
460   EXPECT_EQ("Operation Not Supported", err->reason());
461 }
462 
463 // Verify that we can send traffic back and forth between the clients after a
464 // successful allocate and bind.
TEST_F(RelayServerTest,TestSendRaw)465 TEST_F(RelayServerTest, TestSendRaw) {
466   Allocate();
467   Bind();
468 
469   for (int i = 0; i < 10; i++) {
470     talk_base::scoped_ptr<StunMessage> req(
471         CreateStunMessage(STUN_SEND_REQUEST)), res;
472     AddMagicCookieAttr(req.get());
473     AddUsernameAttr(req.get(), username_);
474     AddDestinationAttr(req.get(), client2_addr);
475 
476     StunByteStringAttribute* send_data =
477         StunAttribute::CreateByteString(STUN_ATTR_DATA);
478     send_data->CopyBytes(msg1);
479     req->AddAttribute(send_data);
480 
481     Send1(req.get());
482     EXPECT_EQ(msg1, ReceiveRaw2());
483     SendRaw2(msg2, static_cast<int>(std::strlen(msg2)));
484     res.reset(Receive1());
485 
486     ASSERT_TRUE(res);
487     EXPECT_EQ(STUN_DATA_INDICATION, res->type());
488 
489     const StunAddressAttribute* src_addr =
490         res->GetAddress(STUN_ATTR_SOURCE_ADDRESS2);
491     ASSERT_TRUE(src_addr != NULL);
492     EXPECT_EQ(1, src_addr->family());
493     EXPECT_EQ(client2_addr.ipaddr(), src_addr->ipaddr());
494     EXPECT_EQ(client2_addr.port(), src_addr->port());
495 
496     const StunByteStringAttribute* recv_data =
497         res->GetByteString(STUN_ATTR_DATA);
498     ASSERT_TRUE(recv_data != NULL);
499     EXPECT_EQ(strlen(msg2), recv_data->length());
500     EXPECT_EQ(0, memcmp(msg2, recv_data->bytes(), recv_data->length()));
501   }
502 }
503 
504 // Verify that a binding expires properly, and rejects send requests.
TEST_F(RelayServerTest,TestExpiration)505 TEST_F(RelayServerTest, TestExpiration) {
506   Allocate();
507   Bind();
508 
509   // Wait twice the lifetime to make sure the server has expired the binding.
510   talk_base::Thread::Current()->ProcessMessages((LIFETIME * 2) * 1000);
511 
512   talk_base::scoped_ptr<StunMessage> req(
513       CreateStunMessage(STUN_SEND_REQUEST)), res;
514   AddMagicCookieAttr(req.get());
515   AddUsernameAttr(req.get(), username_);
516   AddDestinationAttr(req.get(), client2_addr);
517 
518   StunByteStringAttribute* data_attr =
519       StunAttribute::CreateByteString(STUN_ATTR_DATA);
520   data_attr->CopyBytes(msg1);
521   req->AddAttribute(data_attr);
522 
523   Send1(req.get());
524   res.reset(Receive1());
525 
526   ASSERT_TRUE(res.get() != NULL);
527   EXPECT_EQ(STUN_SEND_ERROR_RESPONSE, res->type());
528 
529   const StunErrorCodeAttribute* err = res->GetErrorCode();
530   ASSERT_TRUE(err != NULL);
531   EXPECT_EQ(6, err->eclass());
532   EXPECT_EQ(0, err->number());
533   EXPECT_EQ("Operation Not Supported", err->reason());
534 
535   // Also verify that traffic from the external client is ignored.
536   SendRaw2(msg2, static_cast<int>(std::strlen(msg2)));
537   EXPECT_TRUE(ReceiveRaw1().empty());
538 }
539