File: inject_alive6.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 (180 lines) | stat: -rw-r--r-- 6,292 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
172
173
174
175
176
177
178
179
180
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.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"

extern int thc_socket;
extern char *do_hdr;
extern int do_hdr_off;

int type = 0, passive = 0, active = 0;
char *interface;

void help(char *prg) {
  printf("%s %s (c) 2019 by %s %s\n\n", prg, VERSION, AUTHOR, RESOURCE);
  printf("Syntax: %s [-ap] interface\n\n", prg);
  printf("This tool answers to keep-alive requests on PPPoE and 6in4 tunnels; for PPPoE\nit also sends keep-alive requests.\n");
  printf("Note that the appropriate environment variable THC_IPV6_{PPPOE|6IN4} must be set\n");
  printf("Option -a will actively send alive requests every 15 seconds.\n");
  printf("Option -p will not send replies to alive requests.\n");
  exit(-1);
}

void intercept(u_char *foo, const struct pcap_pkthdr *header, const unsigned char *data) {
  unsigned char *ipv6hdr, *pkt, buf[1500];
  int len = header->caplen, pkt_len = 0;
  unsigned int *seq, offset = 0;
  unsigned short int *orig, *seen;
  thc_ipv6_hdr hdr;
  
  if (debug) {
    printf("DEBUG: packet received\n");
    thc_dump_data((unsigned char *)data, len, "Received packet on tunnel");
  }

  if (type == 2) { // 6in4
    len -= do_hdr_size;
    ipv6hdr = (unsigned char*) (data + do_hdr_size);
    if ((ipv6hdr[0] & 240) != 0x60)
      return;
    if (len < 48 || ipv6hdr[6] != NXT_ICMP6 || ipv6hdr[41] != 0)
      return;
    seq = (unsigned int *) (ipv6hdr + 44);
    if (ipv6hdr[40] == ICMP6_PINGREQUEST) {
      printf("Keep-alive ping request ID 0x%x seen\n", htonl(*seq));
      if (passive == 0) {
        if ((pkt = thc_create_ipv6_extended(interface, PREFER_GLOBAL, &pkt_len, ipv6hdr + 24, ipv6hdr + 8, 255, 0, 0, 0, 0)) == NULL)
          return;
        if (thc_add_icmp6(pkt, &pkt_len, ICMP6_PINGREPLY, 0, htonl(*seq), (unsigned char *) ipv6hdr + 40 + 8, len - 40 - 8, 0) < 0)
          return;
        if (thc_generate_and_send_pkt(interface, NULL, NULL, pkt, &pkt_len) < 0)
          return;
        pkt = thc_destroy_packet(pkt);
        printf("Keep-alive ping reply ID 0x%x sent\n", htonl(*seq));
      }
    }
    if (passive && ipv6hdr[40] == ICMP6_PINGREPLY)
      printf("Keep-alive ping reply ID 0x%x seen\n", htonl(*seq));
  } else { // PPPoE
    seen = (unsigned short int *) (data + 20 + offset + do_hdr_off);
    if (len < 40 || len > 1500 || htons(*seen) != 0xc021)
      return;
    seen = (unsigned short int *) (data + 16 + offset + do_hdr_off);
    if (memcmp(data + 16 + offset + do_hdr_off, do_hdr + 16 + offset + do_hdr_off, 2) != 0) {
      orig = (unsigned short int*) (do_hdr + 16 + offset + do_hdr_off);
      fprintf(stderr, "Warning: PPPoE SessionID is different to that defined in the environment variable! ((specified) %04x != %04x (seen))\n", htons(*orig), htons(*seen));
    }
    if (data[22 + offset + do_hdr_off] == 9) {
      printf("Keep-alive request ID 0x%04x seen\n", htons(*seen));
      if (passive == 0) {
        memcpy(buf + 12, data + 12, len - 12);
        memcpy(buf + 6, data, 6);
        memcpy(buf, data + 6, 6);
        buf[22 + offset + do_hdr_off] = 10;
        hdr.pkt = buf;
        hdr.pkt_len = len;
        if (thc_send_pkt(interface, (unsigned char*) &hdr, &len) < 0) {
          fprintf(stderr, "Error: could not send packet to interface %s (%d)\n", interface, thc_socket);
          exit(-1);
        }
        printf("Keep-alive reply ID 0x%04x sent\n", htons(*seen));
      }
    } else {
      if (passive && data[22 + offset + do_hdr_off] == 10)
        printf("Keep-alive reply ID 0x%04x seen\n", htons(*seen));
    }
  }

  return;
}

int main(int argc, char *argv[]) {
  char sndbuf[128], data[] = { 0x09, 0x0a, 0x00, 0x0c, 0xfa, 0xce, 0xba, 0xbe, 0x1f, 0x1e, 0x1d, 0x1c };
  time_t passed = 0;
  pcap_t *p;
  thc_ipv6_hdr hdr;
  int sndbuflen = 0, i;

  if (argc < 2 || strncmp(argv[1], "-h", 2) == 0)
    help(argv[0]);
    
  while ((i = getopt(argc, argv, "adp")) >= 0) {
    switch(i) {
      case 'a':
        active = 1;
        break;
      case 'd':
        debug = 1;
        break;
      case 'p':
        passive = 1;
        break;
      default:
        fprintf(stderr, "Error: invalid option -%c\n", i);
        exit(-1);
    }
  }

  if (getenv("THC_IPV6_PPPOE") != NULL)
    type = 1;
  else if (getenv("THC_IPV6_6IN4") != NULL)
    type = 2;
    
  if (type == 0) {
    fprintf(stderr, "Error: neither the THC_IPV6_PPPOE nor THC_IPV6_6IN4 environment variable is set\n");
    exit(-1);
  }
  
  if (type == 2 && active)
    fprintf(stderr, "Error: active ping6 sending in for THC_IPV6_6IN4 is not possible. Please use thcping6 or alive6 to perform the active alive packet sending.\n");

  interface = argv[optind];
  
  if (thc_get_own_mac(interface) == NULL) {
    fprintf(stderr, "Error: invalid interface %s\n", interface);
    exit(-1);
  }
  
  printf("Started %s keep-alive watcher on %s (Press Control-C to end) ...\n", type == 1 ? "PPPoE" : "6in4", argv[optind]);
  if (active == 1 && type == 1) {
    if ((p = thc_pcap_init_promisc(interface, "it does not matter what we put here")) == NULL) {
      fprintf(stderr, "Error: Could not set interface into promiscious mode\n");
      exit(-1);
    }
    memcpy(sndbuf, do_hdr, do_hdr_size);
    sndbuf[18 + do_hdr_off] = 0x00;
    sndbuf[19 + do_hdr_off] = sizeof(data) + 2;
    sndbuf[20 + do_hdr_off] = 0xc0;
    sndbuf[21 + do_hdr_off] = 0x21;
    memcpy(sndbuf + do_hdr_size, data, sizeof(data));
    sndbuflen = do_hdr_size + sizeof(data);
    hdr.pkt = sndbuf;
    hdr.pkt_len = sndbuflen;
    
    while (1) {
      thc_pcap_check(p, (char *) intercept, NULL);
      usleep(100);
      if (passed <= time(NULL)) {
        if (thc_send_pkt(interface, (unsigned char*) &hdr, &sndbuflen) < 0) {
          fprintf(stderr, "Error: could not send packet to interface %s\n", interface);
          return -1;
        }
        passed = time(NULL) + 15;
      }
    }
  } else {
    thc_pcap_function(interface, "it does not matter what we put here", (char *) intercept, 1, NULL);
    fprintf(stderr, "Error: Could not set interface into promiscious mode\n");
    exit(-1);
  }

  return -1; // never reached unless error
}