Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 58 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,76 @@

## How it works

RIPv6 uses multiple IP addresses simultaneously. The implementation is based on the rollover concept of the Pre-publish model of DNSSEC keys (ZSK). The first IPv6 address IP1 is generated and actively used. After time factor x, a second IPv6 address IP2 is generated and also actively used straight away for new connections. IP1 reverts to a kind of stand-by status so that it is no longer used for new requests but can still accept responses. When the third IPv6 address IP3 is generated, IP1 switches to rolled status and is deleted from the network adapter. IP2 is now in stand-by status and is also deleted when the next IPv6 address is generated. This cycle carries on endlessly, such that the test system receives new IP addresses and responses never get lost
RIPv6 uses multiple IP addresses simultaneously. The implementation is based on the rollover concept of the Pre-publish model of DNSSEC keys (ZSK).

A precondition for RIPv6 is an existing gateway that carries out the routing of the IPv6 network. The specific address range and this gateway are currently defined in the script itself in the Variables section. This section can also be used to define the time value for the rotation of IP addresses. In a later version these values can also be defined using parameters.

IP addresses in the network range are randomly generated by the GenerateAddress() function, which currently generates addresses for a /64 subnet. Support for /48 networks is planned. The original function itself comes from Vladislav V. Prodan, although I have modified and shortened it for my own purposes.
IP addresses in the network range are randomly generated by the GenerateAddress() function, which currently generates addresses for a /64 subnet. Support for /48 networks is planned. The original function itself comes from Vladislav V. Prodan.

For the rollover concept I establish an endless while loop. The IP addresses generated are assigned to or removed from the network adapter using the ip command. During the first pass, the default route is also configured. This step is only carried out during the first pass.
For the rollover concept I establish an endless while loop. The IP addresses generated are assigned to or removed from the network adapter using the ip command.

## Usage

The script can be started and executed in the background. At the moment every operation (addition and deletion) is output with echo. This way it is clear which IP address is currently being used.
To start the script, you are required to provide 3 environment variables. `INTERFACE`, `NETWORK_ADDR` and `GATEWAY_ADDR`. Otherwise, there are optional environment variables `SLEEP_TIME` and `MAX_IPS`.

```
[user@host ~]# ./ripv6.sh
[+] add ip1 2001:470:26:12b:45dc:2314:b631:4c4a
[*] set default route
[+] add ip2 2001:470:26:12b:9a65:b818:6c96:4271
[+] add ip3 2001:470:26:12b:c15e:ec07:400a:56a2
[-] del ip1 2001:470:26:12b:45dc:2314:b631:4c4a
[+] add ip1 2001:470:26:12b:5326:a7c6:7122:d269
[-] del ip2 2001:470:26:12b:9a65:b818:6c96:4271
[+] add ip2 2001:470:26:12b:ef45:b13a:5665:7ae4
[-] del ip3 2001:470:26:12b:c15e:ec07:400a:56a2
[+] add ip3 2001:470:26:12b:9bd6:6e3d:f90f:8a36
[-] del ip1 2001:470:26:12b:5326:a7c6:7122:d269
[user@host ~]# INTERFACE=eth0 \
NETWORK_ADDR=2a0d:6116:cafe:1337 \
GATEWAY_ADDR=2a0d:6116:cafe::1 \
./ripv6.sh
[*] Configuration:
Interface: eth0
Network: 2a0d:6116:cafe:1337
Gateway: 2a0d:6116:cafe::1
Max IPs: 5
Sleep Time: 5m
[*] Using existing default route via 2a0d:6116:cafe::1
[+] Adding IP: 2a0d:6116:cafe:1337:b867:905b:7469:c5b9
[+] Adding IP: 2a0d:6116:cafe:1337:b867:905b:7469:c5b9
[+] Adding IP: 2a0d:6116:cafe:1337:a542:9bd7:4da4:9053
[+] Adding IP: 2a0d:6116:cafe:1337:6ee5:3c44:394e:df70
[+] Adding IP: 2a0d:6116:cafe:1337:fbab:44f4:c95a:4491
[+] Adding IP: 2a0d:6116:cafe:1337:b58b:216e:cf75:e807
[+] Adding IP: 2a0d:6116:cafe:1337:5119:78de:04af:d008
[-] Removing IP: 2a0d:6116:cafe:1337:b867:905b:7469:c5b9
[+] Adding IP: 2a0d:6116:cafe:1337:9fa6:bd9b:4641:eb05
[-] Removing IP: 2a0d:6116:cafe:1337:a542:9bd7:4da4:9053
[+] Adding IP: 2a0d:6116:cafe:1337:17b0:9551:452e:d792
[-] Removing IP: 2a0d:6116:cafe:1337:6ee5:3c44:394e:df70
...
```

No further modification to the test system is required. The web scanner and other applications can be used as normal. The only difference is that requests are now sent with alternating IP addresses. This means that IP-based blocking should not present an obstacle in the future – provided the website can be accessed through IPv6.
Once terminated, the created ipv6 addresses will be deleted.

No further modification to the system is required. The web scanner and other applications can be used as normal. The only difference is that requests are now sent with alternating IP addresses. This means that IP-based blocking should not present an obstacle in the future – provided the website can be accessed through IPv6.

## Example systemd setup

Since we configure the script variables with environment variables, this can easily be integrated with systemd.

Create a new file in `/etc/systemd/system/`, called `ripv6.service` for example with the following content:

```
[Unit]
Description=IPv6 Address Rotator
After=network.target
Wants=network.target

[Service]
Type=simple
Environment="INTERFACE=eth0"
Environment="NETWORK_ADDR=2a0d:6116:cafe:1337"
Environment="GATEWAY_ADDR=2a0d:6116:cafe::1"
Environment="SLEEP_TIME=5m"
Environment="MAX_IPS=5"
ExecStart=/path/to/RIPv6/ripv6.sh
Restart=on-failure
RestartSec=30

[Install]
WantedBy=multi-user.target
```

## Planned features

The current version is still in the proof-of-concept phase and will receive a number of improvements in future. Plans include use of parameters for the configuration and support of /48 subnets. Any feedback, changes or additions are appreciated.
The current version is still in the proof-of-concept phase and will receive a number of improvements in future. Plans include use of parameters for the configuration and support of /48 subnets. Any feedback, changes or additions are appreciated.
114 changes: 75 additions & 39 deletions ripv6.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
#!/bin/bash
#!/usr/bin/env bash

# -----
# Name: RIPv6
# Copyright (c) 2016 Michael Schneider (scip AG)
# Date: 27-05-2016
# Version: 0.2.3
# Copyright:
# (c) 2016-2025 Michael Schneider (scip AG)
# (c) 2025 Aadniz
# Date: 29-03-2025
# Version: 0.3.0
# -----

# -----
# Variables
# Configurable Variables with defaults
# -----
count=0
cmd_ip="/sbin/ip"
interface="ens33"
network="2001:470:26:12b"
gateway="2001:470:26:12b::1"
sleeptime="30s"
: "${SLEEP_TIME:=5m}"
: "${MAX_IPS:=5}"

# Required Variables
: "${INTERFACE:?Error: INTERFACE environment variable required}"
: "${NETWORK_ADDR:?Error: NETWORK_ADDR environment variable required}"
: "${GATEWAY_ADDR:?Error: GATEWAY_ADDR environment variable required}"

# -----
# Generate Random Address
Expand All @@ -27,41 +30,74 @@ GenerateAddress() {
b=${array[$RANDOM%16]}${array[$RANDOM%16]}${array[$RANDOM%16]}${array[$RANDOM%16]}
c=${array[$RANDOM%16]}${array[$RANDOM%16]}${array[$RANDOM%16]}${array[$RANDOM%16]}
d=${array[$RANDOM%16]}${array[$RANDOM%16]}${array[$RANDOM%16]}${array[$RANDOM%16]}
echo $network:$a:$b:$c:$d
echo $NETWORK_ADDR:$a:$b:$c:$d
}

# -----
# Initial Setup
# -----
echo "[*] Configuration:"
echo " Interface: $INTERFACE"
echo " Network: $NETWORK_ADDR"
echo " Gateway: $GATEWAY_ADDR"
echo " Max IPs: $MAX_IPS"
echo " Sleep Time: $SLEEP_TIME"

# -----
# Gateway Configuration
# -----
if ! ip -6 route show default | grep -q "via $GATEWAY_ADDR dev $INTERFACE"; then
: "${GATEWAY_ADDR:?Error: GATEWAY_ADDR environment variable required and no existing route found}"
echo "[*] Setting default route via $GATEWAY_ADDR"
ip -6 route add default via "$GATEWAY_ADDR" dev "$INTERFACE" || {
echo "[!] Failed to set default route" >&2
exit 1
}
else
echo "[*] Using existing default route via $GATEWAY_ADDR"
# Extract gateway from existing route if not set in environment
if [ -z "$GATEWAY_ADDR" ]; then
GATEWAY_ADDR=$(ip -6 route show default | awk '/via/ {print $3}')
echo "[*] Detected gateway: $GATEWAY_ADDR"
fi
fi

# Cleanup function for trap
cleanup() {
echo -e "\n[*] Received interrupt signal - cleaning up..."
echo "[*] Removing all generated IPs"
for ip in "${current_ips[@]}"; do
ip -6 addr del "$ip"/64 dev $INTERFACE 2>/dev/null
done
exit 0
}

# Set trap for SIGINT (Ctrl+C) and SIGTERM
trap cleanup INT TERM

# Array to store current IPs
declare -a current_ips=()

# -----
# Run IPv6-Address-Loop
# -----
while [ 0=1 ]
while true
do
ip1=$(GenerateAddress)
echo "[+] add ip1 $ip1"
$cmd_ip -6 addr add $ip1/64 dev $interface
if [[ $count == 0 ]]; then
echo "[*] set default route"
$cmd_ip -6 route add default via $gateway dev $interface
fi
if [[ $count > 0 ]]; then
echo "[-] del ip2 $ip2"
$cmd_ip -6 addr del $ip2/64 dev $interface
fi
sleep $sleeptime
# Generate and add new IP
new_ip=$(GenerateAddress)
echo "[+] Added IP: $new_ip"
ip -6 addr add $new_ip/64 dev $INTERFACE

ip2=$(GenerateAddress)
echo "[+] add ip2 $ip2"
$cmd_ip -6 addr add $ip2/64 dev $interface
if [[ $count > 0 ]]; then
echo "[-] del ip3 $ip3"
$cmd_ip -6 addr del $ip3/64 dev $interface
# Remove oldest IP if we've reached MAX_IPS
if [[ ${#current_ips[@]} -ge $MAX_IPS ]]; then
old_ip=${current_ips[0]}
echo "[-] Removing IP: $old_ip"
ip -6 addr del $old_ip/64 dev $INTERFACE
current_ips=("${current_ips[@]:1}") # Remove first element
fi
sleep $sleeptime

ip3=$(GenerateAddress)
echo "[+] add ip3 $ip3"
$cmd_ip -6 addr add $ip3/64 dev $interface
echo "[-] del ip1 $ip1"
$cmd_ip -6 addr del $ip1/64 dev $interface
((count++))
sleep $sleeptime
# Add new IP to array
current_ips+=("$new_ip")

sleep $SLEEP_TIME
done