1
2 /* These are all functions from ethereal, just as they are there */
3
4 /* packet-nbns.c
5 * Routines for NetBIOS-over-TCP packet disassembly (the name dates back
6 * to when it had only NBNS)
7 * Gilbert Ramirez <gram@verdict.uthscsa.edu>
8 * Much stuff added by Guy Harris <guy@netapp.com>
9 *
10 *
11 * Ethereal - Network traffic analyzer
12 * By Gerald Combs <gerald@zing.org>
13 * Copyright 1998 Gerald Combs
14 *
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "names_netbios.h"
36 #include "stats/util.h"
37
38 #define NBNAME_BUF_LEN 128
39 #define BYTES_ARE_IN_FRAME(a, b, c) (((a)+(b)) < (c))
40
41
42 typedef struct
43 {
44 int number;
45 gchar *name;
46 } value_string;
47
48 static const value_string name_type_vals[] = {
49 {0x00, "Workstation/Redirector"},
50 {0x01, "Browser"},
51 {0x02, "Workstation/Redirector"},
52 /* not sure what 0x02 is, I'm seeing alot of them however */
53 /* i'm seeing them with workstation/redirection host
54 announcements */
55 {0x03, "Messenger service/Main name"},
56 {0x05, "Forwarded name"},
57 {0x06, "RAS Server service"},
58 {0x1b, "PDC Domain name"},
59 {0x1c, "BDC Domain name"},
60 {0x1d, "Master Browser backup"},
61 {0x1e, "Browser Election Service"},
62 {0x1f, "Net DDE Service"},
63 {0x20, "Server service"},
64 {0x21, "RAS client service"},
65 {0x22, "Exchange Interchange (MSMail Connector)"},
66 {0x23, "Exchange Store"},
67 {0x24, "Exchange Directory"},
68 {0x2b, "Lotus Notes Server service"},
69 {0x30, "Modem sharing server service"},
70 {0x31, "Modem sharing client service"},
71 {0x43, "SMS Clients Remote Control"},
72 {0x44, "SMS Administrators Remote Control Tool"},
73 {0x45, "SMS Clients Remote Chat"},
74 {0x46, "SMS Clients Remote Transfer"},
75 {0x4c, "DEC Pathworks TCP/IP Service on Windows NT"},
76 {0x52, "DEC Pathworks TCP/IP Service on Windows NT"},
77 {0x6a, "Microsoft Exchange IMC"},
78 {0x87, "Microsoft Exchange MTA"},
79 {0xbe, "Network Monitor Agent"},
80 {0xbf, "Network Monitor Analyzer"},
81 {0x00, NULL}
82 };
83
84
85 /***************************************************************************
86 *
87 * local function definitions
88 *
89 **************************************************************************/
90 static int get_dns_name(const gchar *pd, int offset, int pd_len, char *name, int maxname);
91 static int process_netbios_name(const gchar *name_ptr, char *name_ret, size_t maxname);
92
93
94 /***************************************************************************
95 *
96 * implementation
97 *
98 **************************************************************************/
get_dns_name(const gchar * pd,int offset,int pd_len,char * name,int maxname)99 static int get_dns_name(const gchar *pd, int offset, int pd_len, char *name, int maxname)
100 {
101 const gchar *dp = pd + offset;
102 const gchar *dptr = dp;
103 char *np = name;
104 int len = -1;
105 unsigned int component_len;
106 int dns_data_offset;
107
108 if (offset >= pd_len)
109 goto overflow;
110
111 dns_data_offset = offset;
112
113 maxname--; /* reserve space for the trailing '\0' */
114 for (;;) {
115 if (!BYTES_ARE_IN_FRAME(offset, 1, pd_len))
116 goto overflow;
117 component_len = *dp++;
118 offset++;
119 if (component_len == 0)
120 break;
121 switch (component_len & 0xc0)
122 {
123 case 0x00:
124 /* Label */
125 if (np != name) {
126 /* Not the first component - put in a '.'. */
127 if (maxname > 0) {
128 *np++ = '.';
129 maxname--;
130 }
131 }
132 if (!BYTES_ARE_IN_FRAME(offset, component_len, pd_len))
133 goto overflow;
134 while (component_len > 0) {
135 if (maxname > 0) {
136 *np++ = *dp;
137 maxname--;
138 }
139 component_len--;
140 dp++;
141 offset++;
142 }
143 break;
144
145 case 0x40:
146 case 0x80:
147 goto dns_name_terminated; /* error */
148
149 case 0xc0:
150 /* Pointer. */
151 /* XXX - check to make sure we aren't looping, by keeping track
152 of how many characters are in the DNS packet, and of how many
153 characters we've looked at, and quitting if the latter
154 becomes bigger than the former. */
155 if (!BYTES_ARE_IN_FRAME(offset, 1, pd_len))
156 goto overflow;
157 offset =
158 dns_data_offset + (((component_len & ~0xc0) << 8) | (*dp++));
159 /* If "len" is negative, we are still working on the original name,
160 not something pointed to by a pointer, and so we should set "len"
161 to the length of the original name. */
162 if (len < 0)
163 len = dp - dptr;
164 dp = pd + offset;
165 break; /* now continue processing from there */
166 }
167 }
168
169 dns_name_terminated:
170 *np = '\0';
171 /* If "len" is negative, we haven't seen a pointer, and thus haven't
172 set the length, so set it. */
173 if (len < 0)
174 len = dp - dptr;
175 /* Zero-length name means "root server" */
176 if (*name == '\0')
177 safe_strncpy(name, "<Root>", maxname);
178 return len;
179
180 overflow:
181 /* We ran past the end of the captured data in the packet. */
182 safe_strncpy(name, "<Name goes past end of captured data in packet>", maxname);
183 /* If "len" is negative, we haven't seen a pointer, and thus haven't
184 set the length, so set it. */
185 if (len < 0)
186 len = dp - dptr;
187 return len;
188 }
189
process_netbios_name(const gchar * name_ptr,char * outname,size_t outname_size)190 static int process_netbios_name(const gchar *name_ptr, char *outname, size_t outname_size)
191 {
192 unsigned int i;
193 int name_type = *(name_ptr + NETBIOS_NAME_LEN - 1);
194 gchar name_char;
195 char *name_ret;
196 static const char hex_digits[16] = "0123456780abcdef";
197
198 name_ret = outname;
199 for (i = 0;
200 i < NETBIOS_NAME_LEN - 1 && name_ret-outname < outname_size-1;
201 ++i) {
202 name_char = *name_ptr++;
203 if (name_char >= ' ' && name_char <= '~')
204 *name_ret++ = name_char;
205 else {
206 /* It's not printable; show it as <XX>, where
207 XX is the value in hex. */
208 *name_ret++ = '<';
209 *name_ret++ = hex_digits[(name_char >> 4)];
210 *name_ret++ = hex_digits[(name_char & 0x0F)];
211 *name_ret++ = '>';
212 }
213 }
214 *name_ret = '\0';
215 return name_type;
216 }
217
ethereal_nbns_name(const gchar * pd,int offset,int pd_len,char * outname,size_t outname_size,int * name_type_ret)218 int ethereal_nbns_name(const gchar *pd, int offset, int pd_len,
219 char *outname, size_t outname_size,
220 int *name_type_ret)
221 {
222 int name_len;
223 char name[MAXDNAME];
224 char nbname[NBNAME_BUF_LEN];
225 char buf[16];
226 char *pname, *pnbname, cname, cnbname;
227 int name_type;
228
229 name_len = get_dns_name(pd, offset, pd_len, name, sizeof(name));
230
231 /* OK, now undo the first-level encoding. */
232 pname = &name[0];
233 pnbname = &nbname[0];
234 for (;;) {
235 /* Every two characters of the first level-encoded name
236 * turn into one character in the decoded name. */
237 cname = *pname;
238 if (cname == '\0')
239 break; /* no more characters */
240 if (cname == '.')
241 break; /* scope ID follows */
242 if (cname < 'A' || cname > 'Z') {
243 /* Not legal. */
244 safe_strncpy(nbname,
245 "Illegal NetBIOS name (character not between A and Z in first-level encoding)",
246 sizeof(nbname));
247 goto bad;
248 }
249 cname -= 'A';
250 cnbname = cname << 4;
251 pname++;
252
253 cname = *pname;
254 if (cname == '\0' || cname == '.') {
255 /* No more characters in the name - but we're in
256 * the middle of a pair. Not legal. */
257 safe_strncpy(nbname, "Illegal NetBIOS name (odd number of bytes)", sizeof(nbname));
258 goto bad;
259 }
260 if (cname < 'A' || cname > 'Z') {
261 /* Not legal. */
262 safe_strncpy(nbname,
263 "Illegal NetBIOS name (character not between A and Z in first-level encoding)",
264 sizeof(nbname));
265 goto bad;
266 }
267 cname -= 'A';
268 cnbname |= cname;
269 pname++;
270
271 /* Do we have room to store the character? */
272 if (pnbname < &nbname[NETBIOS_NAME_LEN]) {
273 /* Yes - store the character. */
274 *pnbname = cnbname;
275 }
276
277 /* We bump the pointer even if it's past the end of the
278 name, so we keep track of how long the name is. */
279 pnbname++;
280 }
281
282 /* NetBIOS names are supposed to be exactly 16 bytes long. */
283 if (pnbname - nbname != NETBIOS_NAME_LEN) {
284 /* It's not. */
285 snprintf(nbname, sizeof(nbname), "Illegal NetBIOS name (%ld bytes long)",
286 (long)(pnbname - nbname));
287 goto bad;
288 }
289
290 /* This one is; make its name printable. */
291 name_type = process_netbios_name(nbname, outname, outname_size);
292 snprintf(buf, sizeof(buf), "<%02x>", name_type);
293
294 safe_strncat(outname, buf, outname_size);
295 if (cname == '.') {
296 /* We have a scope ID, starting at "pname"; append that to
297 * the decoded host name. */
298 safe_strncat(outname, pname, outname_size);
299 }
300 if (name_type_ret != NULL)
301 *name_type_ret = name_type;
302 return name_len;
303
304 bad:
305 if (name_type_ret != NULL)
306 *name_type_ret = -1;
307 safe_strncpy(outname, nbname, outname_size);
308 return name_len;
309 }
310
311
312 /* My only code here (JTC) */
313
get_netbios_host_type(int type)314 gchar *get_netbios_host_type(int type)
315 {
316 guint i = 0;
317
318 while (name_type_vals[i].number || name_type_vals[i].name) {
319 if (name_type_vals[i].number == type)
320 return name_type_vals[i].name;
321 i++;
322 }
323
324 return "Unknown";
325 } /* get_netbios_host_type */
326