1 #include <cassert>
2 #include <cstring>
3 #include <iostream>
4 #include <cstdlib>
5 
6 #ifdef WIN32
7 #include <time.h>
8 #else
9 #include <sys/time.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 #include <netinet/in.h>
13 #include <errno.h>
14 #endif
15 
16 #include "udp.h"
17 #include "stun.h"
18 
19 using namespace std;
20 
21 
22 void
usage()23 usage()
24 {
25    cerr << "Usage:" << endl
26 	<< "    ./client stunServerHostname [testNumber] [-v] [-p srcPort] [-i nicAddr1] [-i nicAddr2] [-i nicAddr3]" << endl
27 	<< "For example, if the STUN server was larry.gloo.net, you could do:" << endl
28 	<< "    ./client larry.gloo.net" << endl
29 	<< "The testNumber is just used for special tests." << endl
30 	<< " test 1 runs test 1 from the RFC. For example:" << endl
31 	<< "    ./client larry.gloo.net 0" << endl << endl
32         << endl;
33 }
34 
35 #define MAX_NIC 3
36 
37 int
main(int argc,char * argv[])38 main(int argc, char* argv[])
39 {
40    assert( sizeof(UInt8 ) == 1 );
41    assert( sizeof(UInt16) == 2 );
42    assert( sizeof(UInt32) == 4 );
43 
44    initNetwork();
45 
46    cout << "STUN client version " << STUN_VERSION << endl;
47 
48    int testNum = 0;
49    bool verbose = false;
50 
51    StunAddress4 stunServerAddr;
52    stunServerAddr.addr=0;
53 
54    int srcPort=0;
55    StunAddress4 sAddr[MAX_NIC];
56    int retval[MAX_NIC];
57    int numNic=0;
58 
59    for ( int i=0; i<MAX_NIC; i++ )
60    {
61       sAddr[i].addr=0;
62       sAddr[i].port=0;
63       retval[i]=0;
64    }
65 
66    for ( int arg = 1; arg<argc; arg++ )
67    {
68       if ( !strcmp( argv[arg] , "-v" ) )
69       {
70          verbose = true;
71       }
72       else if ( !strcmp( argv[arg] , "-i" ) )
73       {
74          arg++;
75          if ( argc <= arg )
76          {
77             usage();
78             exit(-1);
79          }
80          if ( numNic >= MAX_NIC )
81          {
82             cerr << "Can not have more than "<<  MAX_NIC <<" -i options" << endl;
83             usage();
84             exit(-1);
85          }
86 
87          stunParseServerName(argv[arg], sAddr[numNic++]);
88       }
89       else if ( !strcmp( argv[arg] , "-p" ) )
90       {
91          arg++;
92          if ( argc <= arg )
93          {
94             usage();
95             exit(-1);
96          }
97          srcPort = strtol( argv[arg], NULL, 10);
98       }
99       else
100       {
101         char* ptr;
102         int t =  strtol( argv[arg], &ptr, 10 );
103         if ( *ptr == 0 )
104         {
105            // conversion worked
106            testNum = t;
107            cout << "running test number " << testNum  << endl;
108         }
109         else
110         {
111            bool ret = stunParseServerName( argv[arg], stunServerAddr);
112            if ( ret != true )
113            {
114               cerr << argv[arg] << " is not a valid host name " << endl;
115               usage();
116               exit(-1);
117            }
118 	}
119       }
120    }
121 
122    if ( srcPort == 0 )
123    {
124       srcPort = stunRandomPort();
125    }
126 
127    if ( numNic == 0 )
128    {
129       // use default
130       numNic = 1;
131    }
132 
133    for ( int nic=0; nic<numNic; nic++ )
134    {
135       sAddr[nic].port=srcPort;
136       if ( stunServerAddr.addr == 0 )
137       {
138          usage();
139          exit(-1);
140       }
141 
142       if (testNum==0)
143       {
144          bool presPort=false;
145          bool hairpin=false;
146 
147          NatType stype = stunNatType( stunServerAddr, verbose, &presPort, &hairpin,
148                                       srcPort, &sAddr[nic]);
149 
150          if ( nic == 0 )
151          {
152             cout << "Primary: ";
153          }
154          else
155          {
156             cout << "Secondary: ";
157          }
158 
159          switch (stype)
160          {
161             case StunTypeFailure:
162                cout << "Some stun error detetecting NAT type";
163 	       retval[nic] = -1;
164                exit(-1);
165                break;
166             case StunTypeUnknown:
167                cout << "Some unknown type error detetecting NAT type";
168 	       retval[nic] = 0xEE;
169                break;
170             case StunTypeOpen:
171                cout << "Open";
172 	       retval[nic] = 0x00;
173                break;
174             case StunTypeIndependentFilter:
175                cout << "Independent Mapping, Independent Filter";
176                if ( presPort ) cout << ", preserves ports"; else cout << ", random port";
177                if ( hairpin  ) cout << ", will hairpin"; else cout << ", no hairpin";
178                retval[nic] = 0x02;
179                break;
180             case StunTypeDependentFilter:
181                cout << "Independedt Mapping, Address Dependendent Filter";
182                if ( presPort ) cout << ", preserves ports"; else cout << ", random port";
183                if ( hairpin  ) cout << ", will hairpin"; else cout << ", no hairpin";
184                retval[nic] = 0x04;
185                break;
186             case StunTypePortDependedFilter:
187                cout << "Indepndent Mapping, Port Dependent Filter";
188                if ( presPort ) cout << ", preserves ports"; else cout << ", random port";
189                if ( hairpin  ) cout << ", will hairpin"; else cout << ", no hairpin";
190                retval[nic] = 0x06;
191                break;
192             case StunTypeDependentMapping:
193                cout << "Dependent Mapping";
194                if ( presPort ) cout << ", preserves ports"; else cout << ", random port";
195                if ( hairpin  ) cout << ", will hairpin"; else cout << ", no hairpin";
196                retval[nic] = 0x08;
197                break;
198             case StunTypeFirewall:
199                cout << "Firewall";
200                retval[nic] = 0x0A;
201                break;
202             case StunTypeBlocked:
203                cout << "Blocked or could not reach STUN server";
204                retval[nic] = 0x0C;
205                break;
206             default:
207                cout << stype;
208                cout << "Unkown NAT type";
209                retval[nic] = 0x0E;  // Unknown NAT type
210                break;
211          }
212          cout << "\t"; cout.flush();
213 
214          if (!hairpin)
215          {
216              retval[nic] |= 0x10;
217          }
218 
219          if (presPort)
220          {
221              retval[nic] |= 0x01;
222          }
223       }
224       else if (testNum==100)
225       {
226          Socket myFd = openPort(srcPort,sAddr[nic].addr,verbose);
227 
228          StunMessage req;
229          memset(&req, 0, sizeof(StunMessage));
230 
231          StunAtrString username;
232          StunAtrString password;
233          username.sizeValue = 0;
234          password.sizeValue = 0;
235 
236          stunBuildReqSimple( &req, username,
237                              false , false ,
238                              0x0c );
239 
240          char buf[STUN_MAX_MESSAGE_SIZE];
241          int len = STUN_MAX_MESSAGE_SIZE;
242 
243          len = stunEncodeMessage( req, buf, len, password,verbose );
244 
245          if ( verbose )
246          {
247             cout << "About to send msg of len " << len
248                  << " to " << stunServerAddr << endl;
249          }
250 
251          while (1)
252          {
253             for ( int i=0; i<100; i++ )
254             {
255                sendMessage( myFd,
256                             buf, len,
257                             stunServerAddr.addr,
258                             stunServerAddr.port,verbose );
259             }
260 #ifdef WIN32 // !cj! TODO - should fix this up in windows
261             clock_t now = clock();
262             assert( CLOCKS_PER_SEC == 1000 );
263             while ( clock() <= now+10 ) { };
264 #else
265             usleep(10*1000);
266 #endif
267          }
268       }
269       else if (testNum==-2)
270       {
271          const int numPort = 5;
272          int fd[numPort];
273          StunAddress4 mappedAddr;
274 
275          for( int i=0; i<numPort; i++ )
276          {
277             fd[i] = stunOpenSocket( stunServerAddr, &mappedAddr,
278                                     (srcPort==0)?0:(srcPort+i), &sAddr[nic],
279                                     verbose );
280             cout << "Got port at " << mappedAddr.port << endl;
281          }
282 
283          for( int i=0; i<numPort; i++ )
284          {
285             closesocket(fd[i]);
286          }
287       }
288       else if (testNum==-1)
289       {
290          int fd3,fd4;
291          StunAddress4 mappedAddr;
292 
293          bool ok = stunOpenSocketPair(stunServerAddr,
294                                       &mappedAddr,
295                                       &fd3,
296                                       &fd4,
297                                       srcPort,
298                                       &sAddr[nic],
299                                       verbose);
300          if ( ok )
301          {
302             closesocket(fd3);
303             closesocket(fd4);
304             cout << "Got port pair at " << mappedAddr.port << endl;
305          }
306          else
307          {
308             cerr << "Opened a stun socket pair FAILED" << endl;
309          }
310       }
311       else
312       {
313          stunTest( stunServerAddr,testNum,verbose,&(sAddr[nic]) );
314       }
315    } // end of for loop
316    cout << endl;
317 
318    UInt32 ret=0;
319    for ( int i=numNic-1; i>=0; i-- )
320    {
321       if ( retval[i] == -1 )
322       {
323          ret = 0xFFFFFFFF;
324          break;
325       }
326       ret = ret << 8;
327       ret = ret | ( retval[i] & 0xFF );
328    }
329 
330    cout << "Return value is " << hex << "0x";
331    cout.fill('0');
332    cout.width(6);
333    cout << ret << dec << endl;
334    cout.fill(' ');
335 
336    return ret;
337 }
338 
339 
340 /* ====================================================================
341  * The Vovida Software License, Version 1.0
342  *
343  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
344  *
345  * Redistribution and use in source and binary forms, with or without
346  * modification, are permitted provided that the following conditions
347  * are met:
348  *
349  * 1. Redistributions of source code must retain the above copyright
350  *    notice, this list of conditions and the following disclaimer.
351  *
352  * 2. Redistributions in binary form must reproduce the above copyright
353  *    notice, this list of conditions and the following disclaimer in
354  *    the documentation and/or other materials provided with the
355  *    distribution.
356  *
357  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
358  *    and "Vovida Open Communication Application Library (VOCAL)" must
359  *    not be used to endorse or promote products derived from this
360  *    software without prior written permission. For written
361  *    permission, please contact vocal@vovida.org.
362  *
363  * 4. Products derived from this software may not be called "VOCAL", nor
364  *    may "VOCAL" appear in their name, without prior written
365  *    permission of Vovida Networks, Inc.
366  *
367  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
368  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
369  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
370  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
371  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
372  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
373  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
374  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
375  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
376  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
377  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
378  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
379  * DAMAGE.
380  *
381  * ====================================================================
382  *
383  * This software consists of voluntary contributions made by Vovida
384  * Networks, Inc. and many individuals on behalf of Vovida Networks,
385  * Inc.  For more information on Vovida Networks, Inc., please see
386  * <http://www.vovida.org/>.
387  *
388  */
389 
390 // Local Variables:
391 // mode:c++
392 // c-file-style:"ellemtel"
393 // c-file-offsets:((case-label . +))
394 // indent-tabs-mode:nil
395 // End:
396