1 /* Poor man's route
2  *
3  * Supported commands:
4  *
5  * "print"
6  * "add" target ["mask" mask] gw ["metric" metric]
7  * "delete" target gw
8  *
9  * Goals:
10  *
11  * Flexible, simple
12  */
13 
14 #define WIN32_NO_STATUS
15 #include <stdarg.h>
16 #include <windef.h>
17 #include <winbase.h>
18 #include <stdio.h>
19 #include <malloc.h>
20 #define _INC_WINDOWS
21 #include <winsock2.h>
22 #include <iphlpapi.h>
23 #include <tchar.h>
24 
25 #define IPBUF 17
26 #define IN_ADDR_OF(x) *((struct in_addr *)&(x))
27 
28 static int Usage()
29 {
30     _ftprintf( stderr,
31                _T("route usage:\n")
32                _T("route print\n")
33                _T("  prints the route table\n")
34                _T("route add <target> [mask <mask>] <gw> [metric <m>]\n")
35                _T("  adds a route\n")
36                _T("route delete <target> <gw>\n")
37                _T("  deletes a route\n") );
38     return 1;
39 }
40 
41 static int PrintRoutes()
42 {
43     PMIB_IPFORWARDTABLE IpForwardTable = NULL;
44     PIP_ADAPTER_INFO pAdapterInfo = NULL;
45     ULONG Size = 0;
46     DWORD Error = 0;
47     ULONG adaptOutBufLen = sizeof(IP_ADAPTER_INFO);
48     TCHAR DefGate[16];
49     TCHAR Destination[IPBUF], Gateway[IPBUF], Netmask[IPBUF];
50     unsigned int i;
51 
52     /* set required buffer size */
53     pAdapterInfo = (IP_ADAPTER_INFO *) malloc( adaptOutBufLen );
54     if (pAdapterInfo == NULL)
55     {
56         Error = ERROR_NOT_ENOUGH_MEMORY;
57         goto Error;
58     }
59     if (GetAdaptersInfo( pAdapterInfo, &adaptOutBufLen) == ERROR_BUFFER_OVERFLOW)
60     {
61        free (pAdapterInfo);
62        pAdapterInfo = (IP_ADAPTER_INFO *) malloc (adaptOutBufLen);
63        if (pAdapterInfo == NULL)
64        {
65            Error = ERROR_NOT_ENOUGH_MEMORY;
66            goto Error;
67        }
68     }
69 
70     if( (GetIpForwardTable( NULL, &Size, TRUE )) == ERROR_INSUFFICIENT_BUFFER )
71     {
72         if (!(IpForwardTable = malloc( Size )))
73         {
74             Error = ERROR_NOT_ENOUGH_MEMORY;
75             goto Error;
76         }
77     }
78 
79     if (((Error = GetAdaptersInfo(pAdapterInfo, &adaptOutBufLen)) == NO_ERROR) &&
80         ((Error = GetIpForwardTable(IpForwardTable, &Size, TRUE)) == NO_ERROR))
81     {
82         _stprintf(DefGate,
83 #ifdef UNICODE
84                   _T("%hs"),
85 #else
86                   _T("%s"),
87 #endif
88                   pAdapterInfo->GatewayList.IpAddress.String);
89         _tprintf(_T("===========================================================================\n"));
90         _tprintf(_T("Interface List\n"));
91         /* FIXME - sort by the index! */
92         while (pAdapterInfo)
93         {
94 #ifdef UNICODE
95             _tprintf(_T("0x%lu ........................... %hs\n"),
96 #else
97             _tprintf(_T("0x%lu ........................... %s\n"),
98 #endif
99                      pAdapterInfo->Index, pAdapterInfo->Description);
100             pAdapterInfo = pAdapterInfo->Next;
101         }
102         _tprintf(_T("===========================================================================\n"));
103 
104         _tprintf(_T("===========================================================================\n"));
105         _tprintf(_T("Active Routes:\n"));
106         _tprintf( _T("%-27s%-17s%-14s%-11s%-10s\n"),
107                   _T("Network Destination"),
108                   _T("Netmask"),
109                   _T("Gateway"),
110                   _T("Interface"),
111                   _T("Metric") );
112         for( i = 0; i < IpForwardTable->dwNumEntries; i++ )
113         {
114             _stprintf( Destination,
115 #ifdef UNICODE
116                        _T("%hs"),
117 #else
118                        _T("%s"),
119 #endif
120                        inet_ntoa( IN_ADDR_OF(IpForwardTable->table[i].dwForwardDest) ) );
121             _stprintf( Netmask,
122 #ifdef UNICODE
123                        _T("%hs"),
124 #else
125                        _T("%s"),
126 #endif
127                        inet_ntoa( IN_ADDR_OF(IpForwardTable->table[i].dwForwardMask) ) );
128             _stprintf( Gateway,
129 #ifdef UNICODE
130                        _T("%hs"),
131 #else
132                        _T("%s"),
133 #endif
134                        inet_ntoa( IN_ADDR_OF(IpForwardTable->table[i].dwForwardNextHop) ) );
135 
136             _tprintf( _T("%17s%17s%17s%16ld%9ld\n"),
137                       Destination,
138                       Netmask,
139                       Gateway,
140                       IpForwardTable->table[i].dwForwardIfIndex,
141                       IpForwardTable->table[i].dwForwardMetric1 );
142         }
143         _tprintf(_T("Default Gateway:%18s\n"), DefGate);
144         _tprintf(_T("===========================================================================\n"));
145         _tprintf(_T("Persistent Routes:\n"));
146 
147         free(IpForwardTable);
148         free(pAdapterInfo);
149 
150         return ERROR_SUCCESS;
151     }
152     else
153     {
154 Error:
155         if (pAdapterInfo) free(pAdapterInfo);
156         if (IpForwardTable) free(IpForwardTable);
157         _ftprintf( stderr, _T("Route enumerate failed\n") );
158         return Error;
159     }
160 }
161 
162 static int convert_add_cmd_line( PMIB_IPFORWARDROW RowToAdd,
163               int argc, TCHAR **argv ) {
164     int i;
165 #ifdef UNICODE
166     char addr[16];
167 #endif
168 
169     if( argc > 1 )
170     {
171 #ifdef UNICODE
172         sprintf( addr, "%ls", argv[0] );
173         RowToAdd->dwForwardDest = inet_addr( addr );
174 #else
175         RowToAdd->dwForwardDest = inet_addr( argv[0] );
176 #endif
177     }
178     else
179         return FALSE;
180     for( i = 1; i < argc; i++ )
181     {
182         if( !_tcscmp( argv[i], _T("mask") ) )
183         {
184             i++; if( i >= argc ) return FALSE;
185 #ifdef UNICODE
186             sprintf( addr, "%ls", argv[i] );
187             RowToAdd->dwForwardMask = inet_addr( addr );
188 #else
189             RowToAdd->dwForwardMask = inet_addr( argv[i] );
190 #endif
191         }
192         else if( !_tcscmp( argv[i], _T("metric") ) )
193         {
194             i++;
195             if( i >= argc )
196                 return FALSE;
197             RowToAdd->dwForwardMetric1 = _ttoi( argv[i] );
198         }
199         else
200         {
201 #ifdef UNICODE
202             sprintf( addr, "%ls", argv[i] );
203             RowToAdd->dwForwardNextHop = inet_addr( addr );
204 #else
205             RowToAdd->dwForwardNextHop = inet_addr( argv[i] );
206 #endif
207         }
208     }
209 
210     return TRUE;
211 }
212 
213 static int add_route( int argc, TCHAR **argv ) {
214     MIB_IPFORWARDROW RowToAdd = { 0 };
215     DWORD Error;
216 
217     if( argc < 2 || !convert_add_cmd_line( &RowToAdd, argc, argv ) )
218     {
219         _ftprintf( stderr,
220                    _T("route add usage:\n")
221                    _T("route add <target> [mask <mask>] <gw> [metric <m>]\n")
222                    _T("  Adds a route to the IP route table.\n")
223                    _T("  <target> is the network or host to add a route to.\n")
224                    _T("  <mask>   is the netmask to use (autodetected if unspecified)\n")
225                    _T("  <gw>     is the gateway to use to access the network\n")
226                    _T("  <m>      is the metric to use (lower is preferred)\n") );
227         return 1;
228     }
229 
230     if( (Error = CreateIpForwardEntry( &RowToAdd )) == ERROR_SUCCESS )
231         return 0;
232 
233     _ftprintf( stderr, _T("Route addition failed\n") );
234     return Error;
235 }
236 
237 static int del_route( int argc, TCHAR **argv )
238 {
239     MIB_IPFORWARDROW RowToDel = { 0 };
240     DWORD Error;
241 
242     if( argc < 2 || !convert_add_cmd_line( &RowToDel, argc, argv ) )
243     {
244         _ftprintf( stderr,
245                     _T("route delete usage:\n")
246                     _T("route delete <target> <gw>\n")
247                     _T("  Removes a route from the IP route table.\n")
248                     _T("  <target> is the network or host to add a route to.\n")
249                     _T("  <gw>     is the gateway to remove the route from.\n") );
250         return 1;
251     }
252 
253     if( (Error = DeleteIpForwardEntry( &RowToDel )) == ERROR_SUCCESS )
254         return 0;
255 
256     _ftprintf( stderr, _T("Route addition failed\n") );
257     return Error;
258 }
259 
260 int _tmain( int argc, TCHAR **argv )
261 {
262     if( argc < 2 )
263         return Usage();
264     else if ( !_tcscmp( argv[1], _T("print") ) )
265         return PrintRoutes();
266     else if( !_tcscmp( argv[1], _T("add") ) )
267         return add_route( argc-2, argv+2 );
268     else if( !_tcscmp( argv[1], _T("delete") ) )
269         return del_route( argc-2, argv+2 );
270     else
271         return Usage();
272 }
273