File: passive_discovery6.c

package info (click to toggle)
thc-ipv6 3.6-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, buster, sid
  • size: 2,116 kB
  • sloc: ansic: 52,618; sh: 529; makefile: 77; perl: 34
file content (171 lines) | stat: -rw-r--r-- 5,286 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <time.h>
#include <pcap.h>
#include "thc-ipv6.h"

#define MAX_ENTRIES 65536

int maxhop = 255, dcnt = 0, do_dst = 0, noverb = 0;
unsigned char d[MAX_ENTRIES + 1][16], hostpart[8];
char *interface, *script = NULL, exec[256], *replace = NULL, *ll;

void help(char *prg) {
  printf("%s %s (c) 2019 by %s %s\n\n", prg, VERSION, AUTHOR, RESOURCE);
  printf("Syntax: %s [-Ds] [-m maxhop] [-R prefix] interface [script]\n\n", prg);
  printf("Options:\n");
  printf(" -D          do also dump destination addresses (does not work with -m)\n");
  printf(" -s          do only print the addresses, no other output\n");
  printf(" -m maxhop   the maximum number of hops a target which is dumped may be away.\n");
  printf("             0 means local only, the maximum amount to make sense is usually 5\n");
  printf(" -R prefix   exchange the defined prefix with the link local prefix\n");
  printf("\nPassivly sniffs the network and dump all client's IPv6 addresses detected.\n");
  printf("Note that in a switched environment you get better results when additionally\nstarting parasite6, however this will impact the network.\n");
  printf("If a script name is specified after the interface, it is called with the\ndetected ipv6 address as first and the interface as second option.\n");
  exit(-1);
}

void detect(u_char *foo, const struct pcap_pkthdr *header, unsigned char *data) {
  char *ptr = data, *ptr2;
  int i, j, k, offset = 8, doit, len = header->caplen;

  if (do_hdr_size) {
    len -= do_hdr_size;
    ptr += do_hdr_size;
    thc_dump_data(ptr, 8, "packet");
    if ((ptr[0] & 240) != 0x60)
      return;
  } else {
    len -= 14;
    ptr += 14;
  }

  // drop ff00::/8 and ::/128
  for (k = 0; k <= do_dst; k++) {
    doit = 0;

    if (ptr[offset] != 0xff
         &&
        ( maxhop > 254 || ptr[7] >= 255 - maxhop || (ptr[7] >= 128 - maxhop && ptr[7] <= 128) || (ptr[7] >= 64 - maxhop && ptr[7] <= 64) )
       )
      doit = 1;
    if (memcmp(ptr + 8, d[dcnt + 1], 16) == 0) {
      if (k == 0 && ptr[7] == 255 && ptr[6] == NXT_ICMP6 && ptr[40] == ICMP6_NEIGHBORSOL && len >= 64) {
        doit = 1;   // DAD packet
        offset = 48;
      } else
        doit = 0;
    }
    
    // is it our own address?
    if (memcmp(ptr + offset + 8, hostpart, 8) == 0)
      doit = 0;

    if (doit) {
      // replace prefix with link-local if -R
      if (replace != NULL)
        if (memcmp(ptr + offset, replace, 8) == 0)
          memcpy(ptr + offset, ll, 8);

      // check for doubles
      j = 0;
      if (dcnt > 0)
        for (i = 0; i < dcnt && j == 0; i++)
          if (memcmp(ptr + offset, d[i], 16) == 0)
            j = 1;
  
      if (j == 0) { // no double
        ptr2 = thc_ipv62notation((char *) (ptr + offset));
        printf("%s%s\n", noverb == 0 ? "Detected: " : "", ptr2);
  
        if (dcnt < MAX_ENTRIES) { // add to double list
          memcpy(d[dcnt], ptr + offset, 16);
          dcnt++;
        } else
          if (dcnt == MAX_ENTRIES) { // table full? should not happen, smells like attack
            dcnt++;
            fprintf(stderr, "Warning: Table for detected IPv6 addresses is full, doubles can occur now!\n");
          }

        if (script != NULL && fork() == 0) { // beware, this can DOS you
          (void) wait3(NULL, WNOHANG, NULL);
          snprintf(exec, sizeof(exec), "%s %s %s\n", script, ptr2, interface);
          if (system(exec) < 0)
            fprintf(stderr, "Error: Executing failed - %s\n", exec);
          exit(0);
        }

        free(ptr2);
      }
    }

    offset += 16;
  }
}

int main(int argc, char *argv[]) {
  int i;
  char *glob;

  if (argc < 2 || strncmp(argv[1], "-h", 2) == 0)
    help(argv[0]);

  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stderr, NULL, _IONBF, 0);
  
  while ((i = getopt(argc, argv, "Dsm:R:")) >= 0) {
    switch (i) {
    case 'm':
      maxhop = atoi(optarg);
      break;
    case 'D':
      do_dst = 1;
      break;
    case 's':
      noverb = 1;
      break;
    case 'R':
      if ((ll = index(optarg, '/')) != NULL)
        *ll = 0;
      replace = thc_resolve6(optarg);
      break;
    default:
      fprintf(stderr, "Error: invalid option %c\n", i);
      exit(-1);
    }
  }

  if (argc - optind < 1 || argc - optind > 2)
    help(argv[0]);
  
  interface = argv[optind];
  if (argc == optind + 2)
    script = argv[optind + 1];

  memset(d, 0, sizeof(d));
  _thc_ipv6_showerrors = 0;

  // we dont want our own address in the discovered addresses
  glob = thc_get_own_ipv6(interface, NULL, PREFER_GLOBAL);
  ll = thc_get_own_ipv6(interface, NULL, PREFER_LINK);
  memcpy(hostpart, ll + 8, 8);
  if (memcmp(ll + 8, glob + 8, 8) != 0) { // do we have a global address with a different host part?
    memcpy(d[0], glob, 16);
    dcnt = 1;
  }
  
  if (do_dst < 255 && do_dst)
    fprintf(stderr, "Warning: it does not make sense to use the -m and -D options together!\n");

  if (noverb == 0)
    printf("Started IPv6 passive system detection (Press Control-C to end) ...\n");
  return thc_pcap_function(interface, "ip6", (char *) detect, 1, NULL);

  return 0; // never reached
}