hping3/random6.c

143 lines
3.5 KiB
C
Raw Permalink Normal View History

2022-04-13 18:01:39 +08:00
// vim:sw=4:ts=4:et:
/*
* Copyright (C) 2021 Andrei Belov (@defanator on github)
*
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
/* 16 octets in binary form + dots between octets + trailing zero */
#define INET6_ADDRBINSTRLEN ((8 * 16) + (1 * 15) + 1UL)
#ifndef INET6_ADDRSTRLEN
#define INET6_ADDRSTRLEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
#endif
char * sprintb(char *dst, void const * const ptr, size_t const size)
{
int i, j;
char *dp = dst;
unsigned char byte;
unsigned char *b = (unsigned char*) ptr;
for (i = size - 1; i >= 0; i--) {
for (j = 7; j >= 0; j--) {
byte = (b[i] >> j) & 1;
*dp++ = byte ? '1' : '0';
}
}
*dp = 0x0;
return dst;
}
char * sprintb_addr6(char *dst, struct in6_addr *in6) {
char *dp = dst;
u_char *p = in6->s6_addr;
int i;
for (i = 0; i < 16; i++) {
sprintb(dp, &p[i], sizeof(u_char));
dp += 8;
if (i < 15) *dp++ = '.';
}
return dst;
}
struct in6_addr ipv6_rand(char *net,uint8_t prefixlen)
{
int i, j, s;
uint8_t bits, shift;
u_char *addr, *mask;
struct in6_addr addr6, mask6,rand6;
//char straddr6[INET6_ADDRSTRLEN];
//char binaddr6[INET6_ADDRBINSTRLEN];
char *ip6net = net;
if (inet_pton(AF_INET6, ip6net, &addr6) < 1) {
printf("incorrect IPv6 address/net: \"%s\"\n", ip6net);
exit(1);
}
addr = addr6.s6_addr;
mask = mask6.s6_addr;
shift = prefixlen;
bits = 128 - shift;
for (i = 0; i < 16; i++) {
s = (shift > 8) ? 8 : shift;
shift -= s;
mask[i] = (u_char) (0xffu << (8 - s));
if (addr[i] != (addr[i] & mask[i])) {
addr[i] &= mask[i];
}
}
//inet_ntop(AF_INET6, &addr6, straddr6, INET6_ADDRSTRLEN);
//printf("network: %s/%d\n", straddr6, prefixlen);
//inet_ntop(AF_INET6, &mask6, straddr6, INET6_ADDRSTRLEN);
//printf("netmask: %s (free bits=%d)\n", straddr6, bits);
//printf("%s\n", sprintb_addr6(binaddr6, &addr6));
//printf("%s\n", sprintb_addr6(binaddr6, &mask6));
//printf("----\n");
srand(((unsigned) getpid() << 16) ^ time(NULL));
uint32_t rv = rand();
int k = 0;
shift = bits;
rand6 = addr6;
addr = rand6.s6_addr;
for (j = 15; j >= 0; j--) {
s = (shift > 8) ? 8 : shift;
shift -= s;
addr[j] = addr[j] ^ ((addr[j] ^ rv) & ~mask[j]);
if (shift == 0) break;
rv >>= 8;
/*
* Note that the MSB of the first octet in random value rv
* will always be 0 as RAND_MAX=0x7FFFFFFF, i.e. if we refresh
* rv after using all the 4 octets from uint32_t, the leading
* bit in octets 4, 8, 12, 16 in generated IPv6 address
* will _always_ be 0.
*
* While it seems legit for e.g. ::ffff:0:0/96 (IPv4-mapped
* addresses), there may be a better way of handling this
* (e.g. refresh rv after using 3 of 4 octets or reverse
* bits in first octet before applying).
*
*/
//if (++k > 2) {
if (++k > 3) {
rv = rand();
k = 0;
}
}
//inet_ntop(AF_INET6, &rand6, straddr6, INET6_ADDRSTRLEN);
//printf("%s [%s]\n", sprintb_addr6(binaddr6, &rand6), straddr6);
return rand6;
}