1 /*
2 * $Id: query.c 45 2010-07-27 07:30:50Z jimklimov $
3 */
4
5 #ifdef HAVE_CONFIG_H
6 #include <config.h>
7 #endif
8
9 #include <ctype.h>
10 #include <errno.h>
11 #include <netdb.h>
12 #include <stdio.h>
13 #include <stdarg.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <arpa/inet.h>
18 #include <netinet/in.h>
19 #include <sys/socket.h>
20 #include <sys/wait.h>
21 #include <sysexits.h>
22
23 #include "sdig.h"
24 #include "common.h"
25 #include "snmpget.h"
26
27 char
findmac_at_rtr_ip(const char * ip,const char * rtr_ip,rtype * rtr)28 *findmac_at_rtr_ip(const char *ip, const char *rtr_ip, rtype *rtr)
29 {
30 char query[256], *ret;
31 int ifnum, eqcheck;
32
33 debug(2, "\n\nfindmac_at_rtr_ip: [%s] [%s] [%s] [%s]\n", ip, rtr_ip, rtr->ip, rtr->pw);
34
35 /* find the router's internal interface number */
36
37 snprintf(query, sizeof(query),
38 "IP-MIB::ipAdEntIfIndex.%s", rtr_ip);
39
40 ifnum = snmpget_int(rtr->ip, rtr->pw, query);
41
42 if (ifnum == -1)
43 return NULL;
44
45 debug(6, "router interface number for %s is %d\n",
46 rtr_ip, ifnum);
47
48 /* now look it up in the net to media table relative to the ifnum */
49
50 /* if digging the router itself, use a different OID */
51
52 eqcheck = strcmp(ip, rtr_ip);
53 if (!eqcheck)
54 snprintf(query, sizeof(query),
55 "interfaces.ifTable.ifEntry.ifPhysAddress.%d",
56 ifnum);
57 else
58 snprintf(query, sizeof(query),
59 "ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress.%d.%s",
60 ifnum, ip);
61
62 ret = snmpget_mac(rtr->ip, rtr->pw, query);
63
64 if (!ret && eqcheck) {
65 // Avaya's have offset OIDs by 1 (maybe VLAN ID reservation?), i.e.
66 // RFC1213-MIB::atPhysAddress.1.1.192.168.42.4 = Hex-STRING: 00 1B 4F 0C 79 E1
67 snprintf(query, sizeof(query),
68 "ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress.%d.1.%s",
69 ifnum, ip);
70
71 ret = snmpget_mac(rtr->ip, rtr->pw, query);
72 }
73
74 return ret;
75 }
76
77 char
findmac(const char * ip,rtype * rtr)78 *findmac(const char *ip, rtype *rtr)
79 {
80 char query[256], *ret;
81 int ifnum;
82
83 debug(2, "\n\nfindmac: [%s] [%s] [%s]\n", ip, rtr->ip, rtr->pw);
84
85 /* find the router's internal interface number */
86 ifnum = -1;
87 ret = NULL;
88
89 if (rtr->rtrip) {
90 /* we have a user-configured rtr_ip */
91
92 debug(2, "\n\nfindmac: an rtr->rtrip is known as [%s]\n", rtr->rtrip);
93
94 ret = findmac_at_rtr_ip(ip, rtr->rtrip, rtr);
95 if ( ret ) {
96 return ret;
97 }
98 }
99
100 if ( (!ret) ) {
101 /* an rtr_ip is not previously known, or the known one
102 doesn't work */
103
104 /* for backward compatibility (sdig-0.43 and before),
105 try rtr->ip address (now intended for SNMP contacts) */
106 ret = findmac_at_rtr_ip(ip, rtr->ip, rtr);
107 if ( ret ) {
108 /* Match on first sight! */
109 if (rtr->rtrip == NULL) {
110 rtr->rtrip = xstrdup(rtr->ip);
111 }
112
113 return ret;
114 };
115
116 if ( !ret ) {
117 /* router's contact IP maybe not in the seeked subnet */
118 /* User may have configured an explicit rtr->rtrip address
119 in the desired subnet; otherwise we'll try to find it
120 and set rtrip value */
121
122 /* This snmpwalking is a TODO for sdig-0.46 */
123
124 ret = NULL;
125 }
126 }
127
128 if ( (!ret) ) {
129 debug(2, "\n\nfindmac: failed to find a router IP\n");
130 return NULL;
131 }
132
133 return ret;
134 }
135
136
137 int
findport(unsigned const char * mac,stype * sw)138 findport(unsigned const char *mac, stype *sw)
139 {
140 char query[64];
141
142 if (sw->ip == NULL) {
143 printf("No switch defined for that network\n");
144 exit(1);
145 }
146
147 /* build the OID for the mapping of MAC addresses to port numbers */
148
149 snprintf(query, sizeof(query), "SNMPv2-SMI::mib-2.17.4.3.1.2.%u.%u.%u.%u.%u.%u",
150 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
151
152 debug(4, "findport: snmpget_int(%s, %s, %s)\n",
153 sw->ip, sw->pw, query);
154
155 return snmpget_int(sw->ip, sw->pw, query);
156 }
157
158 char
getlink(const char * ip,long port)159 *getlink(const char *ip, long port)
160 {
161 litype *tmp;
162
163 tmp = firstli;
164
165 while (tmp) {
166 if ((!strcmp(tmp->ip, ip)) && (tmp->port == port))
167 return tmp->desc;
168
169 tmp = tmp->next;
170 }
171
172 return NULL;
173 }
174
175 char
getdesc(const char * ip,long port)176 *getdesc(const char *ip, long port)
177 {
178 pdtype *tmp;
179
180 tmp = firstpd;
181
182 while (tmp) {
183 if ((!strcmp(tmp->ip, ip)) && (tmp->port == port))
184 return tmp->desc;
185
186 tmp = tmp->next;
187 }
188
189 return NULL;
190 }
191
192 const char
macmfr(unsigned char * inmac)193 *macmfr(unsigned char *inmac)
194 {
195 FILE *macdb;
196 char buf[256], *tmp, macfind[16];
197 int i;
198
199 macdb = fopen(mactable, "r");
200 if (!macdb)
201 return "MAC table file not available";
202
203 /* rewrite the MAC address into something that'll match the table */
204
205 snprintf(macfind, sizeof(macfind), "%02x %02x %02x",
206 inmac[0], inmac[1], inmac[2]);
207
208 while (fgets(buf, sizeof(buf), macdb)) {
209 buf[strlen(buf) - 1] = '\0';
210
211 if (!strncasecmp(buf, macfind, 8)) {
212 tmp = xstrdup(&buf[9]);
213 for (i = strlen(tmp) - 1; i >= 0; i--) {
214 if (!isspace(tmp[i])) {
215 tmp[i+1] = '\0';
216 return tmp;
217 }
218 }
219 return tmp;
220 }
221 }
222
223 fclose(macdb);
224 return "Not available";
225 }
226
227 char
wins_resolve(const char * host)228 *wins_resolve(const char *host)
229 {
230 char exec[256], buf[256];
231 FILE *wq;
232
233 if (!wins) {
234 fprintf(stderr, "WINS not defined in config file!\n");
235 return NULL;
236 }
237
238 if (!nmblookup) {
239 fprintf(stderr, "NMBLOOKUP not defined in config file!\n");
240 return NULL;
241 }
242
243 snprintf(exec, sizeof(exec), "%s -U %s -R %s | tail -1 | cut -f 1 -d \" \"",
244 nmblookup, wins, host);
245
246 debug(5, "popen: %s\n", exec);
247 wq = popen(exec, "r");
248
249 fgets(buf, sizeof(buf), wq);
250 pclose(wq);
251
252 buf[strlen(buf) - 1] = '\0';
253 debug(7, "read [%s]\n", buf);
254 if (!strcmp(buf, "name_query")) {
255 fprintf(stderr, "WINS lookup failed\n");
256 exit(1);
257 }
258
259 printf(" Address: %s (WINS)\n", buf);
260
261 return(xstrdup(buf));
262 }
263
264 char
dns_resolve(const char * host,int verbose)265 *dns_resolve(const char *host, int verbose)
266 {
267 struct hostent *dns;
268 struct in_addr addr;
269
270 if ((dns = gethostbyname(host)) == (struct hostent *) NULL)
271 return NULL;
272
273 memcpy(&addr, dns->h_addr, dns->h_length);
274
275 if ( verbose )
276 printf(" Address: %s (DNS)\n", inet_ntoa(addr));
277
278 return(xstrdup(inet_ntoa(addr)));
279 }
280
281 void
do_ifdescr(stype * sw,long port)282 do_ifdescr(stype *sw, long port)
283 {
284 char query[256], *ifdescr, *ifname, *ifalias;
285 long ifnum;
286
287 /* first get the switch's ifnum for the port */
288
289 snprintf(query, sizeof(query), "SNMPv2-SMI::mib-2.17.1.4.1.2.%ld", port);
290 ifnum = snmpget_int(sw->ip, sw->pw, query);
291
292 if (ifnum == -1)
293 return;
294
295 snprintf(query, sizeof(query), "IF-MIB::ifName.%ld",
296 ifnum);
297
298 ifname = snmpget_str(sw->ip, sw->pw, query);
299
300 /* Unlike previous versions of sdig, we always want an ifAlias:
301 "name" and "desc" fields are nearly the same and almost useless
302 on Cisco Catalyst and HP switches (ifDesc doesn't reflect the
303 switch manager's decription in the switch config, but is just
304 the Switch OS's long version of interface name. */
305 snprintf(query, sizeof(query), "IF-MIB::ifAlias.%ld",
306 ifnum);
307
308 ifalias = snmpget_str(sw->ip, sw->pw, query);
309
310 snprintf(query, sizeof(query), "IF-MIB::ifDescr.%ld",
311 ifnum);
312
313 ifdescr = snmpget_str(sw->ip, sw->pw, query);
314
315 if (ifname) {
316 printf(" (%s)", ifname);
317 free(ifname);
318 }
319
320 if (ifdescr) {
321 printf(" [%s]", ifdescr);
322 free(ifdescr);
323 }
324
325 if (ifalias) {
326 printf(" {%s}", ifalias);
327 free(ifalias);
328 }
329 }
330
331 int
isip(const char * buf)332 isip(const char *buf)
333 {
334 int i;
335
336 for (i = 0; i < strlen(buf); i++)
337 if ((!isdigit(buf[i])) && (buf[i] != '.'))
338 return 0;
339
340 return 1;
341 }
342
343 void
dnsreverse(const char * ip)344 dnsreverse(const char *ip)
345 {
346 struct hostent *dns;
347 struct in_addr addr;
348
349 #if HAVE_INET_ATON
350 inet_aton(ip, &addr);
351 #elif HAVE_INET_PTON
352 inet_pton(AF_INET, ip, &addr);
353 #else
354 #error Cannot convert address
355 #endif
356
357 dns = gethostbyaddr((char *)&addr, sizeof(struct in_addr), AF_INET);
358
359 if (dns)
360 printf(" Hostname: %s (DNS)\n", dns->h_name);
361 }
362
363 stype
find_switch(const char * ipaddr,stype * last)364 *find_switch(const char *ipaddr, stype *last)
365 {
366 stype *tmp, *tmpuniq;
367 int addrchk, swchk;
368
369 if (last)
370 tmp = last->next;
371 else
372 tmp = firstsw;
373
374 if ( ipaddr ) {
375 while (tmp) {
376 /* User requested a specific host/ip */
377 addrchk = ntohl(inet_addr(ipaddr)) & tmp->mask;
378 swchk = tmp->addr & tmp->mask;
379
380 if (swchk == addrchk)
381 return tmp;
382
383 tmp = tmp->next;
384 }
385 } else {
386 /* ipaddr==NULL, check all configured switches */
387 /* NOTE: may check same switch many times, i.e.
388 for Cisco Catalysts - different VLANs require
389 different community strings. */
390
391 /* Check uniquity for same switch IP x COMMUNITY */
392
393 tmpuniq = firstsw;
394 while (tmpuniq != tmp && tmp && tmpuniq) {
395 if (
396 strcmp(tmpuniq->pw, tmp->pw) == 0 &&
397 strcmp(tmpuniq->ip, tmp->ip) == 0
398 ) {
399 /* an earlier switch (tmpuniq) IP x COMMUNITY
400 are the same as our current candidate (tmp)
401 Try next candidate */
402 debug (6, "\nfind_switch: Any_IP mode: switch IP x COMMUNITY already checked: [%s] [%s]\n", tmp->ip, tmp->pw);
403 tmp = tmp->next;
404 }
405 tmpuniq = tmpuniq->next;
406 }
407
408 /* Here we are. TMPUNIQ==TMP (no matches => tmp is unique)
409 or either one is null (end of list) */
410
411 /* The caller will return soon with "tmp"
412 as next starting point */
413 return tmp;
414 } //if
415
416 return NULL;
417 }
418
419 int fork_wrapper(unsigned const char *macaddr, stype *sw);
420
421 /* ask the switch about where the MAC address is */
422 void
switchscan(const char * ipaddr,unsigned const char * macaddr)423 switchscan(const char *ipaddr, unsigned const char *macaddr)
424 {
425 stype *sw;
426 int ret, status;
427
428 printf("\n");
429
430 if (get_debuglevel() >= 2) {
431 debug(2, "switchscan: seeking (%s, ", (ipaddr?ipaddr:"Any_IP"));
432 printmac(macaddr);
433 printf(")\n");
434 }
435
436 sw = find_switch(ipaddr, NULL);
437
438 while (sw) {
439 debug(3, "switchscan: matched %s\n", sw->ip);
440
441 #ifdef SDIG_USE_SEMS
442 if ( dofork ) {
443 /* fflush is needed to correctly pass output
444 * from children when parent's stdout is piped
445 * to elsewhere (file, sdig.cgi wrapper, etc.)
446 * Must be done BOTH before fork and after child labor
447 */
448 fflush(stdout);
449 fflush(stderr);
450 ret = fork();
451
452 switch (ret) {
453 case 0: /* child process */
454
455 ret = fork_wrapper(macaddr, sw);
456 // _exit(EX_OK);
457 debug(3, "child %d done (%d)\n", getpid(), ret);
458
459 fflush(stdout);
460 fflush(stderr);
461 _exit(ret);
462 break;
463
464 case -1:
465 perror("fork");
466 exit(EX_SOFTWARE);
467 break;
468
469 default: /* parent process */
470 debug(3, "child %d started (%s, %s)\n", ret, sw->ip, sw->pw);
471 break;
472 }
473 } else {
474 #endif
475 fork_wrapper(macaddr, sw);
476 #ifdef SDIG_USE_SEMS
477 }
478 #endif
479
480 sw = find_switch(ipaddr, sw);
481 }
482
483 #ifdef SDIG_USE_SEMS
484 if ( dofork ) {
485 while ((ret = wait(&status)) != -1)
486 debug(3, "child %d exited (%d)\n", ret, WEXITSTATUS(status));
487
488 output_sem_cleanup();
489 }
490 #endif
491
492 exit(EX_OK);
493 }
494
495 int
fork_wrapper(unsigned const char * macaddr,stype * sw)496 fork_wrapper(unsigned const char *macaddr, stype *sw)
497 {
498 int port;
499
500 port = findport(macaddr, sw);
501
502 if (port != -1)
503 printport(sw, port);
504
505 debug(3, "findport got port %d\n", port);
506 return port;
507 }
508
509 rtype
find_router(const char * ipaddr,rtype * last)510 *find_router(const char *ipaddr, rtype *last)
511 {
512 rtype *tmp;
513 int addrchk, rtchk;
514
515 if (last)
516 tmp = last->next;
517 else
518 tmp = firstrt;
519
520 while (tmp) {
521 addrchk = ntohl(inet_addr(ipaddr)) & tmp->mask;
522 rtchk = tmp->addr & tmp->mask;
523
524 if (rtchk == addrchk)
525 return tmp;
526
527 tmp = tmp->next;
528 }
529
530 return NULL;
531 }
532
533 /* run the user's script for extra details about a host */
534 void
do_hostinfo(const char * ipaddr)535 do_hostinfo(const char *ipaddr)
536 {
537 char exec[256];
538
539 fflush(stdout);
540
541 snprintf(exec, sizeof(exec), "%s %s", hostinfo, ipaddr);
542 system(exec);
543 }
544
545 /* walk the list of routers checking for the IP address */
546 void
routerscan(const char * ipaddr)547 routerscan(const char *ipaddr)
548 {
549 unsigned char *macaddr;
550 rtype *rtr;
551
552 /* spew out some additional info about the IP address */
553 if (fastmode == 0) {
554 dnsreverse(ipaddr);
555
556 if (hostinfo)
557 do_hostinfo(ipaddr);
558 }
559
560 printf("\n");
561
562 debug(2, "routerscan: looking for a router for host %s\n", ipaddr);
563
564 /* XXX: ping code for waking up sleeping/inactive hosts */
565
566 /* find the first one that covers this network */
567 rtr = find_router(ipaddr, NULL);
568
569 while (rtr) {
570 debug(3, "routerscan: matched %s\n", rtr->ip);
571
572 /* try to find the target IP address on this router */
573 macaddr = findmac(ipaddr, rtr);
574
575 if (macaddr) {
576 printf(" Router: %s - %s\n", rtr->desc, (rtr->rtrip?rtr->rtrip:rtr->ip) );
577
578 printf(" TgtMAC: ");
579 printmac(macaddr);
580 printf(" (%s)\n", macmfr(macaddr));
581
582 switchscan(ipaddr, macaddr);
583 }
584
585 rtr = find_router(ipaddr, rtr);
586 }
587
588 fprintf(stderr, "Error: no routers found for %s\n", ipaddr);
589 exit(1);
590 }
591
592 /* turn <name> into an IP address and pass it to the router scanner */
593 void
resolvename(const char * name)594 resolvename(const char *name)
595 {
596 char *ipaddr;
597
598 /* first try DNS */
599 ipaddr = dns_resolve(name, 1);
600
601 if (ipaddr)
602 routerscan(ipaddr);
603
604 /* now try WINS */
605 ipaddr = wins_resolve(name);
606
607 if (ipaddr)
608 routerscan(ipaddr);
609
610 fprintf(stderr, "Can't resolve %s with DNS or WINS!\n", name);
611 exit(1);
612 }
613
614 /* Different OSes and switches have several ways to write a MAC address.
615 Convert some of these formats to "XX:XX:XX:XX:XX:XX" standard */
616 char
standardize_mac(char * buf)617 *standardize_mac(char *buf)
618 {
619 static char mac[256];
620 char *ptr;
621 char cc, cd, cp, macfmt;
622 int i, j, k;
623
624 /* First pass: count separators, determine known format */
625 cc = 0;
626 cd = 0;
627 cp = 0;
628 for (i = 0; i < strlen(buf); i++) {
629 switch (buf[i]) {
630 case '-':
631 /* Possibly a Windows-format MAC XX-XX-XX-XX-XX-XX */
632 /* or a Hewlett-Packard format XXXXXX-XXXXXX */
633 buf[i] = ':';
634 cd++;
635 break;
636 case ':':
637 cc++;
638 break;
639 case '.':
640 /* Possibly a Cisco format XXXX.XXXX.XXXX */
641 cp++;
642 buf[i] = ':';
643 break;
644 }
645
646 if ((!isxdigit(buf[i])) && (buf[i] != ':')) {
647 fprintf(stderr, "Invalid MAC address specified: %s\n", buf);
648 fprintf(stderr, "Valid characters are hex digits and [:-.]\n");
649 exit(1);
650 }
651 }
652
653 if ( (cd+cc) == 5 ) {
654 /* 6x(0 to 2 hex digits) separated by 5x(dash or doublecolon) */
655 // strncpy (mac, buf, 18);
656 k = 0;
657 for (i = 0, j = 0; i < strlen(buf); i++) {
658 if (
659 ( (i>0 && buf[i-1]==':') || (i==0) ) &&
660 (buf[i] == ':' || buf[i] == '\0' || i==strlen(buf))
661 ) {
662 /* We have a 0-digit long component */
663 mac[j++] = '0'; k++;
664 mac[j++] = '0'; k++;
665 } else {
666 /* We have a 1-digit long component */
667 if (
668 ( (i>0 && buf[i-1]==':') || (i==0) ) &&
669 (buf[i+1] == ':' || buf[i+1] == '\0' || (i+1)==strlen(buf))
670 ) {
671 mac[j++] = '0';
672 k++;
673 }
674 }
675
676 //printf ("%d=%c ",k, buf[i]);
677
678 if ( k>3 ) {
679 mac[j]='\0';
680 fprintf(stderr, "Invalid MAC address specified: %s (%s)\n", buf, mac);
681 fprintf(stderr, "A double-hex component is longer than two characters!\n");
682 exit(1);
683 }
684
685 if ( buf[i] == ':' || buf[i] == '\0' || i==strlen(buf) ) {
686 k=0;
687 }
688
689 if ( j>=17 ) {
690 mac[j]='\0';
691 fprintf(stderr, "Invalid MAC address specified: %s (%s)\n", buf, mac);
692 fprintf(stderr, "String length exceeded!\n");
693 exit(1);
694 }
695
696 mac[j++] = tolower(buf[i]); k++;
697 }
698
699 debug (1, "standardize_mac: got a Windows/Linux/Solaris MAC: [%s]\n", mac);
700 return mac;
701 }
702
703 if ( ((cc+cd+cp) == 0) && (strlen(buf)==12) ) {
704 /* xxxxxxxxxxxx */
705 for (i = 0, j = 0, k = 0; i < strlen(buf); i++) {
706 mac[j++] = tolower(buf[i]); k++;
707 if ( k==2 ) {
708 if ( i < (strlen(buf)-1) ) {
709 k=0;
710 mac[j++] = ':';
711 } else {
712 mac[j++] = '\0';
713 }
714 }
715 }
716
717 debug (1, "standardize_mac: got an unseparated MAC: [%s]\n", mac);
718 return mac;
719 }
720
721 if ( (cd+cc)==1 && (strlen(buf)==13) && buf[6]==':' ) {
722 /* originally Hewlett-Packard: XXXXXX-XXXXXX */
723 for (i = 0, j = 0, k = 0; i < strlen(buf); i++) {
724 if ( i!= 6 ) {
725 mac[j++] = tolower(buf[i]);
726 k++;
727 }
728
729 if ( k==2 ) {
730 if ( i < (strlen(buf)-1) ) {
731 k=0;
732 mac[j++] = ':';
733 } else {
734 mac[j++] = '\0';
735 }
736 }
737 }
738
739 debug (1, "standardize_mac: got a HP MAC: [%s]\n", mac);
740 return mac;
741 }
742
743 if ( (cp+cd+cc)==2 && (strlen(buf)==14) &&
744 buf[4]==':' && buf[9]==':' ) {
745 /* originally Cisco: XXXX.XXXX.XXXX */
746 for (i = 0, j = 0, k = 0; i < strlen(buf); i++) {
747 if ( i!= 4 && i!=9 ) {
748 mac[j++] = tolower(buf[i]);
749 k++;
750 }
751
752 if ( k==2 ) {
753 if ( i < (strlen(buf)-1) ) {
754 k=0;
755 mac[j++] = ':';
756 } else {
757 mac[j++] = '\0';
758 }
759 }
760 }
761
762 debug (1, "standardize_mac: got a Cisco MAC: [%s]\n", mac);
763 return mac;
764 }
765
766
767 strncpy (mac, buf, 18);
768 debug (1, "standardize_mac: unrecognized format, passed on as is: [%s]\n", mac);
769 return mac;
770 }
771
772 /* see if the specified mac address is sane, and make it machine-readable */
773 char
pack_mac(char * buf)774 *pack_mac(char *buf)
775 {
776 int i, cc, sl, v, mp;
777 char *ptr, *cp;
778 static char mac[16];
779
780 cc = 0;
781 for (i = 0; i < strlen(buf); i++) {
782
783 if (buf[i] == '-')
784 /* Possibly a Windows-format MAC XX-XX-XX-XX-XX-XX */
785 buf[i] = ':';
786
787 if (buf[i] == ':')
788 cc++;
789
790 if ((!isxdigit(buf[i])) && (buf[i] != ':')) {
791 fprintf(stderr, "Invalid MAC address specified: %s\n", buf);
792 fprintf(stderr, "Valid characters are hex digits and :\n");
793 exit(1);
794 }
795 }
796
797 if (cc != 5) {
798 fprintf(stderr, "Invalid MAC address specified: %s\n", buf);
799 fprintf(stderr, "It must contain exactly 5 : separators.\n");
800 exit(1);
801 }
802
803 strcpy(mac, "");
804 ptr = buf;
805 sl = strlen(buf);
806 mp = 0;
807
808 for (i = 0; i < sl; i++) {
809 cp = strchr(ptr, ':');
810
811 if (!cp) {
812 v = strtol(ptr, (char **) NULL, 16);
813
814 mac[mp++] = v;
815 break;
816 }
817
818 *cp++ = '\0';
819
820 v = strtol(ptr, (char **) NULL, 16);
821 mac[mp++] = v;
822
823 ptr = cp;
824 }
825
826 return mac;
827 }
828