diff options
133 files changed, 8414 insertions, 7795 deletions
diff --git a/.github/workflows/build-and-run.yml b/.github/workflows/build-and-run.yml index fb6dd798..80d419c7 100644 --- a/.github/workflows/build-and-run.yml +++ b/.github/workflows/build-and-run.yml @@ -14,9 +14,6 @@ jobs: fail-fast: false matrix: include: - - distro: ubuntu-20.04 - pkg-distro: ubuntu20.04 - cpack-type: Ubuntu20 - distro: ubuntu-22.04 pkg-distro: ubuntu22.04 cpack-type: Ubuntu22 @@ -34,7 +31,7 @@ jobs: sudo apt update && NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true sudo -E apt -y install git build-essential cmake gcc linux-headers-`uname -r` - libpcre3-dev libssl-dev liblua5.1-0-dev kmod + libpcre2-dev libssl-dev liblua5.1-0-dev kmod - name: Check out repository code uses: actions/checkout@v3 with: @@ -87,10 +84,11 @@ jobs: [ "debian:11", "debian:12", - "debian:trixie", - "ubuntu:20.04", + "debian:13", + "debian:forky", "ubuntu:22.04", - "ubuntu:24.04" + "ubuntu:24.04", + "ubuntu:devel" ] runs-on: ubuntu-24.04 container: @@ -101,12 +99,13 @@ jobs: HEADERS_SUFFIX=`uname -m | sed s/aarch64/arm64/ | sed s/x86_64/amd64/`; DISTRO=`echo ${{ matrix.distro }} | sed 's/://'`; case "${{ matrix.distro }}" in - debian:trixie) DISTRO=debian13; CPACK_TYPE=Debian13 ;; + debian:forky) DISTRO=debian13; CPACK_TYPE=Debian13 ;; + debian:13) DISTRO=debian13; CPACK_TYPE=Debian13 ;; debian:12) DISTRO=debian12; CPACK_TYPE=Debian12 ;; debian:11) CPACK_TYPE=Debian11 ;; + ubuntu:devel) CPACK_TYPE=Ubuntu24 ; HEADERS_SUFFIX=generic ;; ubuntu:24.04) CPACK_TYPE=Ubuntu24 ; HEADERS_SUFFIX=generic ;; ubuntu:22.04) CPACK_TYPE=Ubuntu22 ; HEADERS_SUFFIX=generic ;; - ubuntu:20.04) CPACK_TYPE=Ubuntu20 ; HEADERS_SUFFIX=generic ;; esac; echo HEADERS_SUFFIX=$HEADERS_SUFFIX >> $GITHUB_ENV; echo DISTRO=$DISTRO >> $GITHUB_ENV; @@ -118,7 +117,7 @@ jobs: apt update && apt -y upgrade && apt -y dist-upgrade && NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true apt -y install git build-essential cmake gcc linux-headers-${{ env.HEADERS_SUFFIX }} - libpcre3-dev libssl-dev liblua5.1-0-dev kmod + libpcre2-dev libssl-dev liblua5.1-0-dev kmod - name: Get kernel name from headers run: > echo KERNEL_NAME=`ls -1 /usr/src/ | grep 'linux-headers.*${{ env.HEADERS_SUFFIX }}' | @@ -177,7 +176,7 @@ jobs: run: > apt update && apt -y upgrade && apt -y dist-upgrade && DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true apt -y install git build-essential cmake gcc - linux-headers-generic libpcre3-dev libssl-dev liblua5.1-0-dev kmod software-properties-common + linux-headers-generic libpcre2-dev libssl-dev liblua5.1-0-dev kmod software-properties-common pkexec dbus linux-base && add-apt-repository -y ppa:cappelikan/ppa && apt update && service dbus start && @@ -222,7 +221,7 @@ jobs: steps: - name: Install build tools run: > - apk update && apk add --no-cache git cmake make g++ pcre-dev libressl-dev linux-headers libucontext-dev lua5.1-dev + apk update && apk add --no-cache git cmake make g++ pcre2-dev libressl-dev linux-headers libucontext-dev lua5.1-dev - name: Check out repository code uses: actions/checkout@v3 with: @@ -248,4 +247,76 @@ jobs: run: sleep 1 - name: Check accel-ppp stat run: accel-cmd show stat -
\ No newline at end of file + + Build-in-Container-Gentoo: + runs-on: ubuntu-24.04 + container: + image: gentoo/stage3 + steps: + - name: Prepare gentoo + run: getuto && emerge --sync + - name: Install build tools + run: | + emerge -g --autounmask-write sys-kernel/gentoo-kernel-bin || (etc-update --verbose --automode -5 && emerge -g sys-kernel/gentoo-kernel-bin) + emerge -g dev-vcs/git dev-libs/libpcre2 dev-build/cmake dev-lang/lua:5.1 + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: mkdir build + run: mkdir build + - name: Disable git security warnings + run: git config --global --add safe.directory '*' + - name: cmake + working-directory: ./build + run: > + cmake -DBUILD_IPOE_DRIVER=TRUE -DBUILD_VLAN_MON_DRIVER=TRUE -DCMAKE_INSTALL_PREFIX=/usr + -DCMAKE_INSTALL_SYSCONFDIR=/etc + -DKDIR=/usr/src/linux + -DLUA=TRUE -DSHAPER=TRUE -DRADIUS=TRUE .. + - name: make and install + working-directory: ./build + run: make && make install + - name: Copy default config + run: cp accel-pppd/accel-ppp.conf /etc/accel-ppp.conf + - name: Start accel-ppp with default config + run: accel-pppd -d -c /etc/accel-ppp.conf + - name: Sleep for 1 sec + run: sleep 1 + - name: Check accel-ppp stat + run: accel-cmd show stat + + Build-in-Container-Fedora: + runs-on: ubuntu-24.04 + container: + image: fedora:rawhide + steps: + - name: Install build tools + run: | + dnf -y install git make cmake gcc pcre2-devel openssl-devel lua-devel kernel-devel + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: mkdir build + run: mkdir build + - name: Disable git security warnings + run: git config --global --add safe.directory '*' + - name: cmake + working-directory: ./build + run: > + cmake -DBUILD_IPOE_DRIVER=TRUE -DBUILD_VLAN_MON_DRIVER=TRUE -DCMAKE_INSTALL_PREFIX=/usr + -DCMAKE_INSTALL_SYSCONFDIR=/etc + -DKDIR=/usr/src/kernels/`ls -1 -t /usr/src/kernels | head -n 1` + -DLUA=TRUE -DSHAPER=TRUE -DRADIUS=TRUE .. + - name: make and install + working-directory: ./build + run: make && make install + - name: Copy default config + run: cp accel-pppd/accel-ppp.conf /etc/accel-ppp.conf + - name: Start accel-ppp with default config + run: accel-pppd -d -c /etc/accel-ppp.conf + - name: Sleep for 1 sec + run: sleep 1 + - name: Check accel-ppp stat + run: accel-cmd show stat diff --git a/.github/workflows/run-tests-32bit.yml b/.github/workflows/run-tests-32bit.yml new file mode 100644 index 00000000..8157f3fb --- /dev/null +++ b/.github/workflows/run-tests-32bit.yml @@ -0,0 +1,171 @@ +name: Run tests (x86_32) + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + Test-in-Alpine-x86-32: + #if: ${{ false }} # disable for now + runs-on: ubuntu-24.04 + name: Test in Qemu (x86_32 Alpine) + strategy: + fail-fast: false + matrix: + distro: [v3.20] + + steps: + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + path: "accel-ppp" + - name: Install build tools for qemu and required tools + run: > + sudo apt update && + NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true + sudo -E apt -y install qemu-system-x86 qemu-utils wget openssh-client screen + - name: Prepare qemu files + run: | + ssh-keygen -t ed25519 -q -N "" -f ssh-key + qemu-img create -f raw disk.raw 5G + wget -nv https://dl-cdn.alpinelinux.org/alpine/${{ matrix.distro }}/releases/x86/netboot/vmlinuz-lts + wget -nv https://dl-cdn.alpinelinux.org/alpine/${{ matrix.distro }}/releases/x86/netboot/initramfs-lts + - name: Run http server for ssh-key + run: | + sudo ip addr add 192.0.2.1/32 dev lo # stable ip for http server + screen -dmS httpserver python3 -m http.server 8000 + - name: Run target OS first time (for setup actions) + run: > + sudo screen -dmS qemu + qemu-system-i386 -accel kvm -M q35 + -m 2048 -smp 2 -nographic + -net nic -net user,hostfwd=tcp::2222-:22 + -drive format=raw,file=disk.raw + -kernel vmlinuz-lts + -initrd initramfs-lts + -append "ip=dhcp alpine_repo=https://dl-cdn.alpinelinux.org/alpine/${{ matrix.distro }}/main + modloop=https://dl-cdn.alpinelinux.org/alpine/${{ matrix.distro }}/releases/x86/netboot/modloop-lts + ssh_key=http://192.0.2.1:8000/ssh-key.pub" + - name: Check that target OS is running + run: | + sleep 1 + sudo screen -ls + - name: Wait for ssh connection + timeout-minutes: 30 + run: > + while ! ssh -o StrictHostKeyChecking=accept-new -p2222 -o ConnectTimeout=5 -i ssh-key root@localhost "exit 0"; + do + echo "Trying to establish ssh connection"; + sleep 5; + done; + cat ~/.ssh/known_hosts + - name: Setup alpine to disk + run: > + ssh -i ssh-key -p2222 root@localhost "setup-alpine -c setup_alpine_conf && + sed -i '/^ROOTSSHKEY\|^DISKOPTS\|^APKREPOSOPTS=/d' setup_alpine_conf && + echo '' >> setup_alpine_conf && + echo 'DISKOPTS=\"-m sys /dev/sda\"' >> setup_alpine_conf && + echo 'ROOTSSHKEY=\"http://192.0.2.1:8000/ssh-key.pub\"' >> setup_alpine_conf && + echo 'APKREPOSOPTS=\"https://dl-cdn.alpinelinux.org/alpine/${{ matrix.distro }}/main\"' >> setup_alpine_conf && + cat setup_alpine_conf && + yes | setup-alpine -e -f setup_alpine_conf" + - name: Poweroff the VM + timeout-minutes: 30 + run: > + ssh -i ssh-key -p2222 root@localhost "poweroff" && + while sudo screen -ls; + do + echo "Waiting for poweroff"; + sleep 5; + done; + - name: Run target OS + run: > + sudo screen -dmS qemu + qemu-system-i386 -accel kvm -M q35 + -m 2048 -smp 2 -nographic + -net nic -net user,hostfwd=tcp::2222-:22 + -drive format=raw,file=disk.raw + - name: Check that target OS is running + run: | + sleep 1 + sudo screen -ls + - name: Wait for ssh connection + timeout-minutes: 30 + run: > + while ! ssh -o StrictHostKeyChecking=accept-new -p2222 -o ConnectTimeout=5 -i ssh-key root@localhost "exit 0"; + do + echo "Trying to establish ssh connection"; + sleep 5; + done; + cat ~/.ssh/known_hosts + - name: Display free space, current dir, kernel version and users + run: | + ssh -i ssh-key -p2222 root@localhost "df -h" + ssh -i ssh-key -p2222 root@localhost "pwd" + ssh -i ssh-key -p2222 root@localhost "uname -a" + ssh -i ssh-key -p2222 root@localhost "cat /etc/passwd" + - name: Install build tools (on target OS) + run: > + ssh -i ssh-key -p2222 root@localhost "setup-apkrepos -o && apk add --no-cache git cmake make g++ pcre2-dev openssl-dev linux-headers libucontext-dev lua5.1-dev linux-lts-dev py3-pip + ppp ppp-pppoe iproute2 dhclient && + (pip3 install pytest pytest-dependency pytest-order || pip3 install --break-system-packages pytest pytest-dependency pytest-order)" + - name: Copy source code to target OS + run: | + tar -Jcf accel-ppp.tar.xz accel-ppp + scp -i ssh-key -P2222 accel-ppp.tar.xz root@localhost: + ssh -i ssh-key -p2222 root@localhost "tar -xf accel-ppp.tar.xz" + - name: Build accel-ppp + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp && git config --global --add safe.directory '*' && + mkdir build && cd build && + cmake -DBUILD_IPOE_DRIVER=TRUE -DBUILD_VLAN_MON_DRIVER=TRUE -DCMAKE_INSTALL_PREFIX=/usr + -DKDIR=/usr/src/linux-headers-\`uname -r\` + -DLUA=TRUE -DSHAPER=TRUE -DRADIUS=TRUE .. && + make && make install" + - name: Run tests (not related to ipoe and vlan_mon drivers) + timeout-minutes: 5 + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp/tests && + python3 -m pytest -Wall --order-dependencies -v -m \"not ipoe_driver and not vlan_mon_driver and not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: ssh -i ssh-key -p2222 -o ConnectTimeout=5 root@localhost "ps aux | grep accel- && dmesg" + - name: Insert ipoe kernel module + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp && + insmod build/drivers/ipoe/driver/ipoe.ko && + lsmod | grep ipoe" + - name: Run tests (not related to vlan_mon drivers) + timeout-minutes: 5 + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp/tests && + python3 -m pytest -Wall --order-dependencies -v -m \"not vlan_mon_driver and not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: ssh -i ssh-key -p2222 -o ConnectTimeout=5 root@localhost "ps aux | grep accel- && dmesg" + - name: Insert vlan_mon kernel module + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp && + insmod build/drivers/vlan_mon/driver/vlan_mon.ko && + lsmod | grep vlan_mon" + - name: Run tests (all) + timeout-minutes: 5 + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp/tests && + python3 -m pytest -Wall --order-dependencies -v -m \"not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: ssh -i ssh-key -p2222 -o ConnectTimeout=5 root@localhost "ps aux | grep accel- && dmesg" + + - name: Check dmesg for kernel issues + if: ${{ always() }} + run: | + ssh -i ssh-key -p2222 -o ConnectTimeout=5 root@localhost "dmesg" > /tmp/dmesg.log + if grep -E 'WARNING: CPU:|BUG:|Oops:|kernel panic|general protection fault|KASAN|UBSAN:|soft lockup|hard LOCKUP|INFO: task .+ blocked|Bad page state|invalid opcode' /tmp/dmesg.log; then + echo "::error::Kernel issues detected in dmesg" + exit 1 + fi diff --git a/.github/workflows/run-tests-asan-ubsan.yml b/.github/workflows/run-tests-asan-ubsan.yml new file mode 100644 index 00000000..8be22b67 --- /dev/null +++ b/.github/workflows/run-tests-asan-ubsan.yml @@ -0,0 +1,84 @@ +name: Run tests with ASAN and UBSAN + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + Test-in-GH-ASAN-UBSAN: + strategy: + fail-fast: false + matrix: + include: + - distro: "ubuntu-latest" + sanitizer: "address" + env_name: "ASAN_OPTIONS" + env_value: "abort_on_error=1:detect_leaks=1:print_stacktrace=1" + - distro: "ubuntu-latest" + sanitizer: "undefined" + env_name: "UBSAN_OPTIONS" + env_value: "print_stacktrace=1" + + runs-on: ${{ matrix.distro }} + steps: + - name: Install build tools (using apt) + run: > + sudo apt update && + NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true sudo -E apt -y install + git build-essential cmake gcc linux-headers-`uname -r` + libpcre2-dev libssl-dev liblua5.1-0-dev kmod python3-pip + iproute2 ppp pppoe isc-dhcp-client + + - name: Install testing tools (using pip) + run: > + sudo apt -y install python3-pytest python3-pytest-dependency python3-pytest-order || + sudo pip3 install pytest pytest-dependency pytest-order || + sudo pip3 install --break-system-packages pytest pytest-dependency pytest-order + + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: mkdir build + run: mkdir build + + - name: cmake (with ${{ matrix.sanitizer }}) + working-directory: ./build + run: > + CFLAGS="-fsanitize=${{ matrix.sanitizer }} -fno-sanitize-recover=all -fno-omit-frame-pointer -O2 -g" + LDFLAGS="-fsanitize=${{ matrix.sanitizer }}" + cmake -DBUILD_IPOE_DRIVER=TRUE -DBUILD_VLAN_MON_DRIVER=TRUE -DCMAKE_INSTALL_PREFIX=/usr + -DKDIR=/usr/src/linux-headers-`uname -r` + -DLUA=TRUE -DSHAPER=TRUE -DRADIUS=TRUE .. + + - name: make && make install + working-directory: ./build + run: make && sudo make install + + - name: Insert and check kernel modules (ipoe and vlan-mon) + # if: ${{ false }} + run: | + sudo insmod build/drivers/vlan_mon/driver/vlan_mon.ko + sudo insmod build/drivers/ipoe/driver/ipoe.ko + lsmod | grep ipoe + lsmod | grep vlan_mon + + - name: Run tests + timeout-minutes: 5 + working-directory: ./tests + env: + ${{ matrix.env_name }}: ${{ matrix.env_value }} + run: sudo -E python3 -m pytest -Wall --order-dependencies -v + + - name: Check dmesg for kernel issues + if: ${{ always() }} + run: | + sudo dmesg | tee /tmp/dmesg.log + if grep -E 'WARNING: CPU:|BUG:|Oops:|kernel panic|general protection fault|KASAN|UBSAN:|soft lockup|hard LOCKUP|INFO: task .+ blocked|Bad page state|invalid opcode' /tmp/dmesg.log; then + echo "::error::Kernel issues detected in dmesg" + exit 1 + fi diff --git a/.github/workflows/run-tests-bigendian.yml b/.github/workflows/run-tests-bigendian.yml new file mode 100644 index 00000000..389cd2a7 --- /dev/null +++ b/.github/workflows/run-tests-bigendian.yml @@ -0,0 +1,199 @@ +name: Run tests (big-endian) + +on: + workflow_dispatch: + pull_request: + push: + branches: + - master + +jobs: + + Test-in-Alpine-s390x: + #if: ${{ false }} # disable for now + runs-on: ubuntu-24.04 + name: Test in Qemu (s390x Alpine) + + steps: + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + path: "accel-ppp" + - name: Install build tools for qemu and required tools + run: > + sudo apt update && + NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true + sudo -E apt -y install wget openssh-client screen + libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev libslirp-dev ninja-build + - name: Build Qemu 9.1.2 + # Qemu 8.2 from Ubuntu24.04 has critical s390x-related bugs so Qemu9 is required + run: | + wget -nv https://github.com/qemu/qemu/archive/refs/tags/v9.1.2.tar.gz + tar -xf v9.1.2.tar.gz + cd qemu-9.1.2 + ./configure --target-list=s390x-softmmu --enable-slirp + make -j + sudo make install + - name: Prepare qemu files + run: | + ssh-keygen -t ed25519 -q -N "" -f ssh-key + qemu-img create -f raw disk.raw 5G + wget -nv https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/s390x/netboot/vmlinuz-lts + wget -nv https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/s390x/netboot/initramfs-lts + - name: Run http server for ssh-key + run: | + sudo ip addr add 192.0.2.1/32 dev lo # stable ip for http server + screen -dmS httpserver python3 -m http.server 8000 + - name: Run target OS first time (for setup actions) + run: > + sudo screen -dmS qemu -L -Logfile qemu-console-setup.log + qemu-system-s390x -M s390-ccw-virtio + -m 4096 -smp 2 -nographic + -net nic -net user,hostfwd=tcp::2222-:22 + -drive format=raw,file=disk.raw + -kernel vmlinuz-lts + -initrd initramfs-lts + -append "ip=dhcp alpine_repo=https://dl-cdn.alpinelinux.org/alpine/v3.20/main + modloop=https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/s390x/netboot/modloop-lts + ssh_key=http://192.0.2.1:8000/ssh-key.pub" + - name: Check that target OS is running + run: | + sleep 1 + sudo screen -ls + - name: Wait for ssh connection + timeout-minutes: 30 + run: > + while ! ssh -o StrictHostKeyChecking=accept-new -p2222 -o ConnectTimeout=5 -i ssh-key root@localhost "exit 0"; + do + echo "Trying to establish ssh connection"; + sleep 5; + done; + cat ~/.ssh/known_hosts + - name: Wait for disk to be available + # virtio_blk is not in the netboot initramfs; it comes from the modloop + # image the VM downloads at boot. If that download fails, sshd still + # comes up but /dev/vda never appears, so retry the modloop service + # until the disk is visible. + timeout-minutes: 10 + run: > + while ! ssh -i ssh-key -p2222 root@localhost "test -e /sys/block/vda/device"; + do + echo "Disk not visible, retrying modloop download"; + ssh -i ssh-key -p2222 root@localhost + "rc-service modloop restart; rc-service hwdrivers restart; modprobe virtio_blk 2>/dev/null; ls /lib/modules" || true; + sleep 10; + done + - name: Setup alpine to disk + run: > + ssh -i ssh-key -p2222 root@localhost "setup-alpine -c setup_alpine_conf && + sed -i '/^ROOTSSHKEY\|^DISKOPTS\|^APKREPOSOPTS=/d' setup_alpine_conf && + echo '' >> setup_alpine_conf && + echo 'DISKOPTS=\"-m sys /dev/vda\"' >> setup_alpine_conf && + echo 'ROOTSSHKEY=\"http://192.0.2.1:8000/ssh-key.pub\"' >> setup_alpine_conf && + echo 'APKREPOSOPTS=\"https://dl-cdn.alpinelinux.org/alpine/v3.20/main\"' >> setup_alpine_conf && + cat setup_alpine_conf && + yes | setup-alpine -e -f setup_alpine_conf" + - name: Poweroff the VM + timeout-minutes: 30 + run: > + ssh -i ssh-key -p2222 root@localhost "poweroff" && + while sudo screen -ls; + do + echo "Waiting for poweroff"; + sleep 5; + done; + - name: Run target OS + run: > + sudo screen -dmS qemu -L -Logfile qemu-console.log + qemu-system-s390x -M s390-ccw-virtio + -m 4096 -smp 2 -nographic + -net nic -net user,hostfwd=tcp::2222-:22 + -drive format=raw,file=disk.raw + - name: Check that target OS is running + run: | + sleep 1 + sudo screen -ls + - name: Wait for ssh connection + timeout-minutes: 30 + run: > + while ! ssh -o StrictHostKeyChecking=accept-new -p2222 -o ConnectTimeout=5 -i ssh-key root@localhost "exit 0"; + do + echo "Trying to establish ssh connection"; + sleep 5; + done; + cat ~/.ssh/known_hosts + - name: Display free space, current dir, kernel version and users + run: | + ssh -i ssh-key -p2222 root@localhost "df -h" + ssh -i ssh-key -p2222 root@localhost "pwd" + ssh -i ssh-key -p2222 root@localhost "uname -a" + ssh -i ssh-key -p2222 root@localhost "cat /etc/passwd" + - name: Install build tools (on target OS) + run: > + ssh -i ssh-key -p2222 root@localhost "setup-apkrepos -o && apk add --no-cache git cmake make g++ pcre2-dev openssl-dev linux-headers libucontext-dev lua5.1-dev linux-lts-dev py3-pip + ppp ppp-pppoe iproute2 dhclient && + (pip3 install pytest pytest-dependency pytest-order || pip3 install --break-system-packages pytest pytest-dependency pytest-order)" + - name: Copy source code to target OS + run: | + tar -Jcf accel-ppp.tar.xz accel-ppp + scp -i ssh-key -P2222 accel-ppp.tar.xz root@localhost: + ssh -i ssh-key -p2222 root@localhost "tar -xf accel-ppp.tar.xz" + - name: Build accel-ppp + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp && git config --global --add safe.directory '*' && + mkdir build && cd build && + cmake -DBUILD_IPOE_DRIVER=TRUE -DBUILD_VLAN_MON_DRIVER=TRUE -DCMAKE_INSTALL_PREFIX=/usr + -DKDIR=/usr/src/linux-headers-\`uname -r\` + -DLUA=TRUE -DSHAPER=TRUE -DRADIUS=TRUE .. && + make && make install" + - name: Run tests (not related to ipoe and vlan_mon drivers) + timeout-minutes: 5 + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp/tests && + python3 -m pytest -Wall --order-dependencies -v -m \"not ipoe_driver and not vlan_mon_driver and not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: ssh -i ssh-key -p2222 -o ConnectTimeout=5 root@localhost "ps aux | grep accel- && dmesg" + - name: Insert ipoe kernel module + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp && + insmod build/drivers/ipoe/driver/ipoe.ko && + lsmod | grep ipoe" + - name: Run tests (not related to vlan_mon drivers) + timeout-minutes: 5 + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp/tests && + python3 -m pytest -Wall --order-dependencies -v -m \"not vlan_mon_driver and not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: ssh -i ssh-key -p2222 -o ConnectTimeout=5 root@localhost "ps aux | grep accel- && dmesg" + - name: Insert vlan_mon kernel module + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp && + insmod build/drivers/vlan_mon/driver/vlan_mon.ko && + lsmod | grep vlan_mon" + - name: Run tests (all) + timeout-minutes: 5 + run: > + ssh -i ssh-key -p2222 root@localhost "cd accel-ppp/tests && + python3 -m pytest -Wall --order-dependencies -v -m \"not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: ssh -i ssh-key -p2222 -o ConnectTimeout=5 root@localhost "ps aux | grep accel- && dmesg" + + - name: Check dmesg for kernel issues + if: ${{ always() }} + run: | + ssh -i ssh-key -p2222 -o ConnectTimeout=5 root@localhost "dmesg" > /tmp/dmesg.log + if grep -E 'WARNING: CPU:|BUG:|Oops:|kernel panic|general protection fault|KASAN|UBSAN:|soft lockup|hard LOCKUP|INFO: task .+ blocked|Bad page state|invalid opcode' /tmp/dmesg.log; then + echo "::error::Kernel issues detected in dmesg" + exit 1 + fi + - name: Display QEMU console logs + if: ${{ always() }} + run: | + for f in qemu-console-setup.log qemu-console.log; do + echo "===== $f =====" + sudo cat "$f" || true + done diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 3f8016a8..71b3820b 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -26,11 +26,6 @@ jobs: untar: false format: qcow2 - - distro: Ubuntu-20.04 - image: https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img - untar: false - format: qcow2 - - distro: Debian13 image: https://cloud.debian.org/images/cloud/trixie/daily/latest/debian-13-generic-amd64-daily.tar.xz untar: true @@ -56,8 +51,8 @@ jobs: run: > sudo apt update && NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true sudo -E apt -y install qemu-system-x86 qemu-utils cloud-image-utils cpu-checker cloud-image-utils wget openssh-client screen - - name: Check kvm support (fail is ok) - run: sudo kvm-ok || exit 0 + - name: Check kvm support + run: sudo kvm-ok - name: Prepare cloud-init image disk run: | ssh-keygen -t ed25519 -q -N "" -f ssh-key @@ -91,9 +86,9 @@ jobs: wget -nv ${{ matrix.image }} -O img/image qemu-img resize -f ${{ matrix.format }} img/`ls -1 img` +2G - name: Run target OS first time (for cloud-init actions) - run: sudo qemu-system-x86_64 -m 4096 -nographic -drive format=${{ matrix.format }},file=img/`ls -1 img` -drive format=raw,file=init.img + run: sudo qemu-system-x86_64 -enable-kvm -cpu host -m 4096 -nographic -drive format=${{ matrix.format }},file=img/`ls -1 img` -drive format=raw,file=init.img - name: Run target OS - run: sudo screen -dmS qemu qemu-system-x86_64 -net nic -net user,hostfwd=tcp::2222-:22 -m 4096 -nographic -drive format=${{ matrix.format }},file=img/`ls -1 img` + run: sudo screen -dmS qemu qemu-system-x86_64 -enable-kvm -cpu host -net nic -net user,hostfwd=tcp::2222-:22 -m 4096 -nographic -drive format=${{ matrix.format }},file=img/`ls -1 img` - name: Check that target OS is running run: | sleep 1 @@ -117,10 +112,12 @@ jobs: run: > ssh -i ssh-key -p2222 user@localhost "sudo apt -y install git build-essential cmake gcc linux-headers-\`uname -r\` - libpcre3-dev libssl-dev liblua5.1-0-dev kmod python3-pip + libpcre2-dev libssl-dev liblua5.1-0-dev kmod python3-pip libxml2-dev libxslt1-dev zlib1g-dev iproute2 ppp pppoe isc-dhcp-client timelimit && - (sudo pip3 install pytest pytest-dependency || sudo pip3 install --break-system-packages pytest pytest-dependency)" + (sudo apt -y install python3-pytest python3-pytest-dependency python3-pytest-order || + sudo pip3 install pytest pytest-dependency pytest-order || + sudo pip3 install --break-system-packages pytest pytest-dependency pytest-order)" - name: Copy source code to target OS run: | tar -Jcf accel-ppp.tar.xz accel-ppp @@ -139,7 +136,7 @@ jobs: timeout-minutes: 5 run: > ssh -i ssh-key -p2222 user@localhost "cd accel-ppp/tests && - sudo python3 -m pytest -Wall -v -m \"not ipoe_driver and not vlan_mon_driver\"" + sudo python3 -m pytest -Wall --order-dependencies -v -m \"not ipoe_driver and not vlan_mon_driver\"" - name: Display processes and dmesg after tests if: ${{ always() }} run: > @@ -157,7 +154,7 @@ jobs: if: ${{ always() }} run: > ssh -i ssh-key -p2222 user@localhost "cd accel-ppp/tests && - sudo python3 -m pytest -Wall -v -m \"not vlan_mon_driver\"" + sudo python3 -m pytest -Wall --order-dependencies -v -m \"not vlan_mon_driver\"" - name: Display processes and dmesg after tests if: ${{ always() }} run: > @@ -173,20 +170,168 @@ jobs: - name: Run tests (all) timeout-minutes: 5 run: > - ssh -i ssh-key -p2222 user@localhost "cd accel-ppp/tests && - sudo python3 -m pytest -Wall -v" + ssh -i ssh-key -p2222 user@localhost "cd accel-ppp/tests && + sudo python3 -m pytest -Wall --order-dependencies -v" - name: Display processes and dmesg after tests if: ${{ always() }} run: > - ssh -i ssh-key -p2222 user@localhost "ps aux | grep accel- && + ssh -i ssh-key -p2222 user@localhost "ps aux | grep accel- && sudo dmesg" + - name: Check dmesg for kernel issues + if: ${{ always() }} + run: | + ssh -i ssh-key -p2222 user@localhost "sudo dmesg" > /tmp/dmesg.log + if grep -E 'WARNING: CPU:|BUG:|Oops:|kernel panic|general protection fault|KASAN|UBSAN:|soft lockup|hard LOCKUP|INFO: task .+ blocked|Bad page state|invalid opcode' /tmp/dmesg.log; then + echo "::error::Kernel issues detected in dmesg" + exit 1 + fi + + Test-in-Alpine: + #if: ${{ false }} # disable for now + runs-on: ubuntu-24.04 + name: Test in Qemu (Alpine) + + steps: + - name: Check out repository code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + path: "accel-ppp" + - name: Install qemu and required tools + run: > + sudo apt update && + NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true sudo -E apt -y install qemu-system-x86 qemu-utils cloud-image-utils cpu-checker cloud-image-utils wget openssh-client screen + - name: Check kvm support + run: sudo kvm-ok + - name: Prepare cloud-init image disk + run: | + ssh-keygen -t ed25519 -q -N "" -f ssh-key + echo "instance-id: $(uuidgen || echo i-abcdefg)" > init-meta + echo "#cloud-config" > init-data + echo "package_update: true" >> init-data + echo "package_upgrade: true" >> init-data + echo "package_reboot_if_required: false" >> init-data + echo "users:" >> init-data + echo " - default" >> init-data + echo " - name: alpine" >> init-data + echo " shell: /bin/bash" >> init-data + echo " ssh_authorized_keys:" >> init-data + echo " - "`cat ssh-key.pub` >> init-data + echo "power_state:">> init-data + echo " mode: poweroff">> init-data + cat init-data + cloud-localds init.img init-data init-meta + - name: Download and resize target OS cloud image + run: | + mkdir img + # we need to use metal image because virt image doesn't provide pppoe driver (https://gitlab.alpinelinux.org/alpine/aports/-/issues/13739) + wget -nv https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/cloud/nocloud_alpine-3.20.3-x86_64-bios-cloudinit-metal-r0.qcow2 -O img/image + qemu-img resize -f qcow2 img/`ls -1 img` +2G + - name: Run target OS first time (for cloud-init actions) + run: sudo qemu-system-x86_64 -enable-kvm -cpu host -m 4096 -nographic -drive format=qcow2,file=img/`ls -1 img` -drive format=raw,file=init.img + - name: Run target OS + run: sudo screen -dmS qemu qemu-system-x86_64 -enable-kvm -cpu host -net nic -net user,hostfwd=tcp::2222-:22 -m 4096 -nographic -drive format=qcow2,file=img/`ls -1 img` + - name: Check that target OS is running + run: | + sleep 1 + sudo screen -ls + - name: Wait for ssh connection + timeout-minutes: 30 + run: > + while ! ssh -o StrictHostKeyChecking=accept-new -p2222 -o ConnectTimeout=5 -i ssh-key alpine@localhost "exit 0"; + do + echo "Trying to establish ssh connection"; + sleep 5; + done; + cat ~/.ssh/known_hosts + - name: Display free space, current dir, kernel version and test doas + run: | + ssh -i ssh-key -p2222 alpine@localhost "df -h" + ssh -i ssh-key -p2222 alpine@localhost "pwd" + ssh -i ssh-key -p2222 alpine@localhost "uname -a" + ssh -i ssh-key -p2222 alpine@localhost "doas cat /etc/passwd" + - name: Install build tools (on target OS) + run: > + ssh -i ssh-key -p2222 alpine@localhost "doas apk add --no-cache git cmake make g++ pcre2-dev libressl-dev linux-headers libucontext-dev lua5.1-dev linux-lts-dev py3-pip + ppp ppp-pppoe && + (doas pip3 install pytest pytest-dependency pytest-order || doas pip3 install --break-system-packages pytest pytest-dependency pytest-order)" + - name: Copy source code to target OS + run: | + tar -Jcf accel-ppp.tar.xz accel-ppp + scp -i ssh-key -P2222 accel-ppp.tar.xz alpine@localhost: + ssh -i ssh-key -p2222 alpine@localhost "tar -xf accel-ppp.tar.xz" + - name: Build accel-ppp + run: > + ssh -i ssh-key -p2222 alpine@localhost "cd accel-ppp && + mkdir build && cd build && + cmake -DBUILD_IPOE_DRIVER=TRUE -DBUILD_VLAN_MON_DRIVER=TRUE -DCMAKE_INSTALL_PREFIX=/usr + -DKDIR=/usr/src/linux-headers-\`uname -r\` + -DLUA=TRUE -DSHAPER=TRUE -DRADIUS=TRUE .. && + make && doas make install" + + - name: Run tests (not related to ipoe and vlan_mon drivers) + timeout-minutes: 5 + run: > + ssh -i ssh-key -p2222 alpine@localhost "cd accel-ppp/tests && + doas python3 -m pytest -Wall --order-dependencies -v -m \"not ipoe_driver and not vlan_mon_driver and not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: > + ssh -i ssh-key -p2222 alpine@localhost "ps aux | grep accel- && + doas dmesg" + + - name: Insert ipoe kernel module + run: > + ssh -i ssh-key -p2222 alpine@localhost "cd accel-ppp && + doas insmod build/drivers/ipoe/driver/ipoe.ko && + lsmod | grep ipoe " + + - name: Run tests (not related to vlan_mon drivers) + timeout-minutes: 5 + if: ${{ always() }} + run: > + ssh -i ssh-key -p2222 alpine@localhost "cd accel-ppp/tests && + doas python3 -m pytest -Wall --order-dependencies -v -m \"not vlan_mon_driver and not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: > + ssh -i ssh-key -p2222 alpine@localhost "ps aux | grep accel- && + doas dmesg" + + - name: Insert vlan_mon kernel module + run: > + ssh -i ssh-key -p2222 alpine@localhost "cd accel-ppp && + doas insmod build/drivers/vlan_mon/driver/vlan_mon.ko && + lsmod | grep vlan_mon" + + - name: Run tests (all) + timeout-minutes: 5 + run: > + ssh -i ssh-key -p2222 alpine@localhost "cd accel-ppp/tests && + doas python3 -m pytest -Wall --order-dependencies -v -m \"not chap_secrets\"" + - name: Display processes and dmesg after tests + if: ${{ always() }} + run: > + ssh -i ssh-key -p2222 alpine@localhost "ps aux | grep accel- && + doas dmesg" + + - name: Check dmesg for kernel issues + if: ${{ always() }} + run: | + ssh -i ssh-key -p2222 alpine@localhost "doas dmesg" > /tmp/dmesg.log + if grep -E 'WARNING: CPU:|BUG:|Oops:|kernel panic|general protection fault|KASAN|UBSAN:|soft lockup|hard LOCKUP|INFO: task .+ blocked|Bad page state|invalid opcode' /tmp/dmesg.log; then + echo "::error::Kernel issues detected in dmesg" + exit 1 + fi + + Test-in-GH: #if: ${{ false }} # disable for now strategy: fail-fast: false matrix: - distro: ["ubuntu-24.04", "ubuntu-22.04", "ubuntu-20.04"] + distro: ["ubuntu-24.04", "ubuntu-22.04"] runs-on: ${{ matrix.distro }} steps: @@ -195,12 +340,14 @@ jobs: sudo apt update && NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true sudo -E apt -y install git build-essential cmake gcc linux-headers-`uname -r` - libpcre3-dev libssl-dev liblua5.1-0-dev kmod python3-pip + libpcre2-dev libssl-dev liblua5.1-0-dev kmod python3-pip iproute2 ppp pppoe isc-dhcp-client - name: Install testing tools (using pip) run: > - sudo pip3 install pytest pytest-dependency || sudo pip3 install --break-system-packages pytest pytest-dependency + sudo apt -y install python3-pytest python3-pytest-dependency python3-pytest-order || + sudo pip3 install pytest pytest-dependency pytest-order || + sudo pip3 install --break-system-packages pytest pytest-dependency pytest-order - name: Check out repository code uses: actions/checkout@v4 @@ -232,14 +379,23 @@ jobs: - name: Run tests timeout-minutes: 5 working-directory: ./tests - run: sudo python3 -m pytest -Wall -v + run: sudo python3 -m pytest -Wall --order-dependencies -v + + - name: Check dmesg for kernel issues + if: ${{ always() }} + run: | + sudo dmesg | tee /tmp/dmesg.log + if grep -E 'WARNING: CPU:|BUG:|Oops:|kernel panic|general protection fault|KASAN|UBSAN:|soft lockup|hard LOCKUP|INFO: task .+ blocked|Bad page state|invalid opcode' /tmp/dmesg.log; then + echo "::error::Kernel issues detected in dmesg" + exit 1 + fi Test-in-GH-Coverage: #if: ${{ false }} # disable for now strategy: fail-fast: false matrix: - distro: ["ubuntu-24.04", "ubuntu-22.04", "ubuntu-20.04"] + distro: ["ubuntu-24.04", "ubuntu-22.04"] runs-on: ${{ matrix.distro }} steps: @@ -248,12 +404,14 @@ jobs: sudo apt update && NEEDRESTART_SUSPEND=1 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true sudo -E apt -y install git build-essential cmake gcc linux-headers-`uname -r` - libpcre3-dev libssl-dev liblua5.1-0-dev kmod python3-pip + libpcre2-dev libssl-dev liblua5.1-0-dev kmod python3-pip iproute2 ppp pppoe isc-dhcp-client - - name: Install testing tools (using pip) + - name: Install testing tools run: > - sudo pip3 install pytest pytest-dependency gcovr || sudo pip3 install --break-system-packages pytest pytest-dependency gcovr + sudo apt -y install python3-pytest python3-pytest-dependency python3-pytest-order gcovr || + sudo pip3 install pytest pytest-dependency pytest-order gcovr || + sudo pip3 install --break-system-packages pytest pytest-dependency pytest-order gcovr - name: Check out repository code uses: actions/checkout@v4 @@ -286,7 +444,16 @@ jobs: - name: Run tests (for coverage report) (fail is ok) timeout-minutes: 5 working-directory: ./tests - run: sudo python3 -m pytest -Wall -v || exit 0 + run: sudo python3 -m pytest -Wall --order-dependencies -v || exit 0 + + - name: Check dmesg for kernel issues + if: ${{ always() }} + run: | + sudo dmesg | tee /tmp/dmesg.log + if grep -E 'WARNING: CPU:|BUG:|Oops:|kernel panic|general protection fault|KASAN|UBSAN:|soft lockup|hard LOCKUP|INFO: task .+ blocked|Bad page state|invalid opcode' /tmp/dmesg.log; then + echo "::error::Kernel issues detected in dmesg" + exit 1 + fi - name: Generate coverage reports (default(txt), csv, html) run: | diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..cbce9ec7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,43 @@ +# Changelog + +## Unreleased + +### Features +- New `metrics` module: HTTP endpoint exposing the same numbers as `accel-cmd show stat` at `/metrics`, in either Prometheus exposition or JSON format. Configurable listen address and optional IPv4 CIDR allow-list. + +## 1.14.0 - 2026-01-24 + +### Breaking / Compatibility +- Crypto: removed bundled tomcrypt; OpenSSL-only builds. +- Regex: migrated from libpcre to libpcre2. +- Build: raised minimum CMake version (3.10+). +- Build: MUSL detection and conditional linking; additional Entware/Gentoo compatibility fixes. + +### Features +- CLI: new `show ippool` command. +- RADIUS: Message-Authenticator blast attack protection. +- RADIUS: Framed-Interface-Id support in `radattr`. +- SSTP: load certificate chain (not just single cert). +- PPPoE/IPoE/L2TP/SSTP: multiple protocol improvements (see fixes). + +### Fixes +- PPPoE: RFC2516 tag parsing compliance; ignore vendor-specific tags in PADR; missing break fix. +- PPPoE: additional RFC2516 PADI tag parsing fixes. +- PPP LCP: truncate echo reply when larger than client MRU. +- L2TP: fix buffer overflow and Calling/Called Number handling; include calling number in Calling-Station-ID. +- IPoE: DHCP noauth username fix; DHCP option 42 fix; kernel 6.12 driver fixes. +- IPoE: build fixes for newer kernels (NETIF_F_NETNS_LOCAL, del_timer/timer_delete, flowi4_tos). +- IPv6: DHCPv6 Confirm support; RFC6334 AFTR-Name support. +- Accounting: preserve last counters on disconnect. +- RADIUS: refresh session stats in req_set_stat; restrict DM/CoA sources. +- Logging: fix log_tcp memory leak. +- Shaper: TBF leaf-qdisc support and clsact policer support; tbf leaf-qdisc fix. +- Misc: GCC14/musl/big-endian build fixes; net-snmp 5.9.4+ compatibility; connlimit/pptp fix; post_msg bug fix; SSTP HTTP replay handling fix. + +### Docs +- Expanded documentation for PPPoE/IPoE/SSTP/L2TP/PPP/RADIUS/IPPools, certs, proxy protocol. + +### Tests / CI +- Added asan/ubsan runs, 32-bit and big-endian test jobs, and broader distro coverage; expanded pytest coverage. +- New or updated CI targets: Ubuntu 24.04 default runner, Fedora rawhide, Debian 13, Ubuntu devel, Gentoo, Alpine (including s390x), plus KVM speedups. +- Removed/disabled outdated or flaky jobs and tests (Ubuntu 20, Debian 10, Alpine chap-secrets); added more pcre/pppoe/ipoe test coverage. diff --git a/CMakeLists.txt b/CMakeLists.txt index 128b75a9..9aee13be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.6) +cmake_minimum_required(VERSION 3.10) if (CMAKE_BINARY_DIR STREQUAL CMAKE_HOME_DIRECTORY) message(FATAL_ERROR "Building in source directory is forbidden. Please make separated build directory.") @@ -7,6 +7,7 @@ endif () project(accel-ppp C) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fno-strict-aliasing -D_GNU_SOURCE -fPIC -rdynamic -Wno-unused-result") +ADD_DEFINITIONS(-DOPENSSL_API_COMPAT=0x10100000L) IF (NOT DEFINED LIB_SUFFIX) EXECUTE_PROCESS( @@ -20,18 +21,33 @@ IF (NOT DEFINED LIB_SUFFIX) ENDIF (ARCH STREQUAL x86_64) ENDIF (NOT DEFINED LIB_SUFFIX) +# Set flag if we are building with MUSL +IF (CMAKE_SYSTEM_NAME STREQUAL Linux AND CMAKE_C_COMPILER_ID STREQUAL GNU) + execute_process( + COMMAND sh -c "ldd --version 2>&1 || true" + OUTPUT_VARIABLE LDD_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if (LDD_VERSION MATCHES "[Mm]usl") + set(MUSL ON) + else () + set(MUSL OFF) + endif () + message(STATUS "Building with MUSL: ${MUSL}") +ENDIF (CMAKE_SYSTEM_NAME STREQUAL Linux AND CMAKE_C_COMPILER_ID STREQUAL GNU) + #color console example message(FATAL_ERROR "${Esc}[31m Red Text ${Esc}[m Restore Normal Text") string(ASCII 27 Esc) -#Check libpcre -find_library(PCRE_LIBRARY pcre +#Check libpcre2 +find_library(PCRE2_LIBRARY pcre2-8 HINTS ${CMAKE_SOURCE_DIR}/lib/linux/gcc/${BIT}/lib PATHS ${CMAKE_SOURCE_DIR}/lib/linux/gcc/${BIT}/lib ) -IF(NOT PCRE_LIBRARY) - message(FATAL_ERROR "${Esc}[31mRequired libpcre not found.\n Install libpcre3-dev and run cmake again${Esc}[m") -ENDIF(NOT PCRE_LIBRARY) +IF(NOT PCRE2_LIBRARY) + message(FATAL_ERROR "${Esc}[31mRequired libpcre not found.\n Install libpcre2-dev and run cmake again${Esc}[m") +ENDIF(NOT PCRE2_LIBRARY) IF (EXISTS ${CMAKE_HOME_DIRECTORY}/.git AND NOT IGNORE_GIT) @@ -40,9 +56,9 @@ IF (EXISTS ${CMAKE_HOME_DIRECTORY}/.git AND NOT IGNORE_GIT) WORKING_DIRECTORY ${CMAKE_HOME_DIRECTORY} OUTPUT_VARIABLE ACCEL_PPP_VERSION ) - STRING(STRIP ${ACCEL_PPP_VERSION} ACCEL_PPP_VERSION) + STRING(STRIP "${ACCEL_PPP_VERSION}" ACCEL_PPP_VERSION) ELSE (EXISTS ${CMAKE_HOME_DIRECTORY}/.git AND NOT IGNORE_GIT) - SET (ACCEL_PPP_VERSION 1.13.0) + SET (ACCEL_PPP_VERSION 1.14.0) ENDIF (EXISTS ${CMAKE_HOME_DIRECTORY}/.git AND NOT IGNORE_GIT) # we must include cpack.cmake after generating the ACCEL_PPP_VERSION variable @@ -57,33 +73,16 @@ if (NOT BUILD_DRIVER_ONLY) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector -fstack-protector-all") endif (MEMDEBUG) - if (NOT DEFINED CRYPTO) - set(CRYPTO OPENSSL) - endif (NOT DEFINED CRYPTO) - - if (CRYPTO STREQUAL OPENSSL) - find_library(CRYPTO_LIBRARY ssl - HINTS ${CMAKE_SOURCE_DIR}/lib/linux/gcc/${BIT}/lib - PATHS ${CMAKE_SOURCE_DIR}/lib/linux/gcc/${BIT}/lib - ) - IF(NOT CRYPTO_LIBRARY) - message(FATAL_ERROR "${Esc}[31mRequired libcrypto-0.9.8 or probably later (openssl-0.9.8) not found.\n Install libssl-dev and run cmake again${Esc}[m") - ENDIF(NOT CRYPTO_LIBRARY) - add_definitions(-DCRYPTO_OPENSSL) - set(crypto_lib crypto ssl) - elseif (CRYPTO STREQUAL TOMCRYPT) - add_definitions(-DCRYPTO_TOMCRYPT) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/crypto) - set(crypto_lib tomcrypt internal-crypto) - elseif (CRYPTO STREQUAL INTERNAL) - INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/crypto) - set(crypto_lib internal-crypto) - else (CRYPTO STREQUAL OPENSSL) - message(FATAL_ERROR "unknown CRYPTO type") - endif (CRYPTO STREQUAL OPENSSL) + find_library(CRYPTO_LIBRARY ssl + HINTS ${CMAKE_SOURCE_DIR}/lib/linux/gcc/${BIT}/lib + PATHS ${CMAKE_SOURCE_DIR}/lib/linux/gcc/${BIT}/lib + ) + IF(NOT CRYPTO_LIBRARY) + message(FATAL_ERROR "${Esc}[31mRequired libcrypto-0.9.8 or probably later (openssl-0.9.8) not found.\n Install libssl-dev and run cmake again${Esc}[m") + ENDIF(NOT CRYPTO_LIBRARY) + set(crypto_lib crypto ssl) add_subdirectory(accel-pppd) - add_subdirectory(crypto) add_subdirectory(accel-cmd) install(DIRECTORY DESTINATION /var/log/accel-ppp) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..7db14516 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# Contributing + +Thanks for helping improve accel-ppp. Please keep changes focused and easy to review. + +## Code style and quality +- The current style in this repository is evolving and not yet uniform. +- New contributions are expected to follow improved styling standards as we gradually improve the codebase. +- For C, follow Linux kernel style (K&R-like), unless a file clearly follows a different local convention: + - Use hard tabs for indentation (8-column tab stops); avoid spaces for leading indent. + - This matches existing files and avoids alignment issues in different editors. + - Function definitions: opening brace on the next line. + - Control blocks (`if/for/while/switch`): opening brace on the same line. + - `else` and `while` (for do-while) align with the closing brace. +- Prefer this layout: + +```c +int foo(int x) +{ + if (x > 0) { + bar(x); + } else { + baz(); + } +} +``` + - References: + - Linux kernel coding style: `https://www.kernel.org/doc/html/latest/process/coding-style.html` + - K&R brace/indent style overview: `https://en.wikipedia.org/wiki/Indentation_style` +- Prefer small, focused functions and avoid unnecessary refactoring or cosmetic churn. + +## Commits (recommended, not strictly enforced) +- Use concise, imperative messages (e.g., "cli: fix output formatting"). +- A simple component prefix is helpful but not required. +- Squash or group related changes when it improves clarity. + +## AI-generated or assisted code +- We do not have a final policy decision yet. +- If you use AI assistance, you must review and edit your patches. +- Obvious slop, hallucinations, or nonsense will be rejected immediately. + +## Tests and documentation +- Run relevant tests when possible; note what you ran in the PR/commit. +- Update documentation and man pages if behavior or options change. + +## PR acceptance criteria +- New features or improvements must provide clear value to the accel-ppp community. +- Changes should not break existing behavior unless it is truly necessary; in such cases, contributors must make all reasonable efforts to provide a clear migration/adaptation path for users. +- Relevant tests must pass. +- Submissions must be testable by maintainers and reviewers. +- For bug fixes where trigger conditions are unclear, maintainers/reviewers may ask for details needed to reproduce the issue. + +## PR review process +- We aim to review PRs within 1 week. +- If there is no maintainer activity, maintainers may be unavailable (volunteers) or the PR is too complex to review quickly. +- For major functionality changes or behavior changes, please discuss first before submitting a PR. + +## Review expectations +- Please respond to review comments and update the PR as requested. +- Be prepared to rebase or adjust commits if asked by maintainers. diff --git a/README b/README deleted file mode 100644 index 143c5e13..00000000 --- a/README +++ /dev/null @@ -1,181 +0,0 @@ -Overview --------- -The ACCEL-PPP v1.0 is completly new implementation of PPTP/PPPoE/L2TP/SSTP which was written from scratch. -Userspace daemon has its own PPP implementation, so it does not uses pppd and one process (multi-threaded) manages all connections. -ACCEL-PPP uses kernel-mode implementations of pptp/l2tp/pppoe and user-mode of sstp. - - -Features --------- -1. Modular architecture -2. High-performance multi-threaded I/O core -3. Supported PPTP -4. Supported PPPoE (including TR-101 extension) -5. Supported L2TPv2 (without IPsec) -5. Radius authentication/accounting -6. Radius DM/CoA extention -7. Supported authentication types: PAP, CHAP (md5), Microsoft CHAP Extentions (including version 2), not supported - EAP -8. Supported MPPE -9. Compression is not supported -10. Extensible logging engine with per session logging support, implemented log to file, log to remote host and log to PostgreSQL targets -11. Extensible user/password database, implemented Radius, pppd compatible chap-secrets sources -12. Extensible IP pool, implemented Radius, chap-secrets and static pools -13. Supported pppd compatible ip-up/ip-down scripts -14. Builtin tbf/htb shaper and clsact policer manager -15. Command line interface via telnet -16. SNMP support (master or subagent via AgentX) -17. Supported SSTP - - -Requirment ----------- -1. modern linux distribution -2. kernel-2.6.25 or later -4. cmake-2.6 or later -5. libnl-2.0 or probably later (required for builtin shaper) -6. libcrypto-0.9.8 or probably later (openssl-0.9.8) -7. libpcre -8. net-snmp-5.x -9. libssl-0.9.8 or probably later (openssl-0.9.8) - - -Compilation and instalation ------------ -Make sure you have configured kernel headers in /usr/src/linux, -or specify other location via KDIR. -1. cd /path/to/accel-ppp-1.3.5 -2. mkdir build -3. cd build -4. cmake [-DBUILD_DRIVER=FALSE] [-DKDIR=/usr/src/linux] [-DCMAKE_INSTALL_PREFIX=/usr/local] [-DCMAKE_BUILD_TYPE=Release] [-DLOG_PGSQL=FALSE] [-DSHAPER=FALSE] [-DRADIUS=TRUE] [-DNETSNMP=FALSE] .. - Please note that the double dot record in the end of the command is essential. You'll probably get error or misconfigured sources if you miss it. - BUILD_DRIVER, KDIR, CMAKE_INSTALL_PREFIX, CMAKE_BUILD_TYPE, LOG_PGSQL, SHAPER, RADIUS are optional, - But while pptp is not present in mainline kernel you probably need BUILD_DRIVER. - For example: - cmake -DBUILD_DRIVER=TRUE .. - will configure sources to build pptp driver, search kernel headers at /usr/src/linux, install to /usr/local, - build with no debug, pgsql and shaper support, build with radius support. -5. If you want to use chap-secrets for authentication purpose then you need to disable radius support, configure as following: - cmake -DBUILD_DRIVER=TRUE -DRADIUS=FALSE .. - of course you can include additional options if needed. -6. make -7. make install - - -Configuration -------------- -read man accel-ppp.conf - - -Built-in shaper --------------- -accel-ppp supports tbf and htb based shaper manager. It also supports clsact policer manager. -To enable it uncomment shaper in [modules] section. -It accepts radius attributes in various formats: rate, down-rate/up-rate and cisco-like. Values have to be in kilobits except cisco-like. -For example: -Filter-Id=1000 (means 1000Kbit both up-stream and down-stream rate) -Filter-Id=2000/3000 (means 2000Kbit down-stream rate and 3000Kbit up-stream rate) -To change radius attribute which containes rate information use 'attr' option, for example: -[shaper] -attr=My-Custom-Rate-Attribute -of course this attribute have to be in radius dictionary. -To specify different attributes for down-stream and up-stream rates use 'attr-down' and 'attr-up' options, for example: -[shaper] -attr-down=PPPD-Downstream-Speed -attr-up=PPPD-Upstream-Speed - -If you want to use cisco-like format configure accel-ppp as following: -[shaper] -vendor=Cisco -attr=Cisco-AVPair -and send two attributes: -Cisco-AVPair=lcp:interface-config#1=rate-limit input 2000000 8000 8000 conform-action transmit exceed-action drop (which means 2000Kbit up-stream rate and 8Kb burst) -Cisco-AVPair=lcp:interface-config#1=rate-limit output 2000000 8000 8000 conform-action transmit exceed-action drop (which means 2000Kbit down-stream rate and 8Kb burst) - - -Advanced shaper using ---------------------- -1. Burst configuration. -If you not using cisco-like format then burst calculates from rate and specified burst factors. -To specify burst factors use 'down-burst-factor' and 'up-burst-factor' options, for example: -[shaper] -down-burst-factor=1.0 -up-burst-factor=10.0 -which means that burst for tbf/htb qdisc will be calculated as down-stream rate multiply to 1.0 and burst for policer/htb will be calculated as up-stream rate multiply to 10.0. - -2. Time ranges. -You can specify time ranges to authomatic rate reconfiguration. -To specify time ranges use following sample configuration: -[shaper] -time-range=1,1:00-3:00 -time-range=2,3:00-5:00 -time-range=3,5:00-7:00 -first number is time range identifier. -To specify time range specific rates use following format of radius attributes: range-id,rate, range-id,down-rate/up-rate or cisco-like, for example: -Filter-Id=1000 -Filter-Id=1,2000 -Filter-Id=2,3000 -Filter-Id=3,4000 -which means: set 1000Kbit by default, set 2000Kbit in time range 1, set 3000Kbit in time range 2, set 4000Kbit in time range 3. -You have to pass multiple Filter-Id attributes to utilize this functionality. -Or cisco-like: -Cisco-AVPair=lcp:interface-config#1=rate-limit output access-group 1 1000000 8000 8000 conform-action transmit exceed-action drop -Cisco-AVPair=lcp:interface-config#1=rate-limit input access-group 1 1000000 8000 8000 conform-action transmit exceed-action drop -and so on... - -3. chap-secrets. -If you use chap-secrets instead of radius then there is way to utilize built-in shaper too. -The optional fifth column in chap-secrets file is used to pass rate information to shaper. -Its format is same as for radius attributes, except you cann't utilize time ranges functionality. - - -SNMP ----- -SNMP is implemented using net-snmp libraries. By default accel-ppp starts in subagent mode, -so make sure that net-snmp configured with subagent control turned on (read net-snmp's README.agentx for more details). -Also you can start accel-ppp as master agent using following configuration: -[snmp] -master=1 - -Usage: -Place accel-pppd/extra/net-snmp/ACCEL-PPP-MIB.txt to your mibs directory. -Also you can find used numerical oids in this file. -1. Requesting statistics: -snmpwalk -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::accelPPPStat -2. Requesting sessions: -snmptable -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::sessionsTable -3. Terminate session by session identifier (Acct-Session-ID): -snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termBySID.0 = 0000000000000001 -4. Terminate session by interface name: -snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIfName.0 = ppp2 -5. Terminaten session by IP address (Framed-IP-Address): -snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIP.0 = 192.168.10.10 -6. Terminate session by username: -snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByUsername.0 = user1 -7. Execute cli command: -snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::cli.0 = "shaper change all 1024 temp" - - -chap-secrets encryption ------------------------ -To enable chap-secrets encryption ablity accel-ppp must be compiled with -DCRYPTO=OPENSSL (which is default). -Username field may be kept as cleartext or hashed through some hash chain. To specify hash chain use username-hash option. -For example, username-hash=md5,sha1 means hash username through md5 and then binary result hash through sha1. -Username have to be specified as hexadecimal dump of digest result. -Password field have to be encrypted using smbencrypt (NT Hash part). -Encryption is incompatible with auth_chap_md5 module. - - -Warning !!! ------------ -1. The pptp driver conflicts with ip_gre driver (in kernel), so make sure that ip_gre is not built-in or loaded at run time - (don't matter if you have 2.6.37 or later kernel). -2. Don't mix connections of accel-ppp and poptop's pptpd, before starting accel-ppp make sure that no connections - of pptpd exists. - - -Contacts --------- -http://accel-ppp.org/ -mail: contact@accel-ppp.org -ICQ: 337258064 -Jabber: dima@accel-ppp.org diff --git a/README.md b/README.md new file mode 100644 index 00000000..2ce25b5f --- /dev/null +++ b/README.md @@ -0,0 +1,254 @@ +ACCEL-PPP +========= + +ACCEL-PPP is a high-performance, multi-threaded VPN and broadband access +concentrator for Linux. It has its own userspace PPP implementation, so one +daemon can manage all connections without relying on pppd. The implementation +was developed from scratch rather than as a wrapper around pppd. It uses Linux +kernel interfaces for PPTP, L2TP, and PPPoE data paths, while SSTP is handled in +userspace. + + +Features +======== + +* Modular architecture and a multi-threaded I/O core +* PPTP, PPPoE (including TR-101), L2TPv2, SSTP, and IPoE. ACCEL-PPP does not + provide integrated IPsec for L2TPv2; deploy IPsec separately when required. +* RADIUS authentication and accounting, including Disconnect Messages and + Change of Authorization (DM/CoA) +* PAP, CHAP-MD5, MS-CHAPv1, and MS-CHAPv2 authentication +* Microsoft Point-to-Point Encryption (MPPE) +* File, syslog, TCP, and optional PostgreSQL logging, including per-session logs +* Extensible authentication sources, including RADIUS and pppd-compatible + chap-secrets files +* Extensible IP address pools populated by RADIUS, chap-secrets, or static + configuration +* pppd-compatible ip-up and ip-down scripts +* TBF/HTB shaping and clsact policing +* Telnet and TCP command-line interfaces +* Optional SNMP support as a master agent or AgentX subagent + +EAP authentication and PPP compression are not supported. + + +Requirements +============ + +Building the daemon requires: + +* Linux +* A C compiler and standard build tools +* CMake 3.10 or newer +* OpenSSL development files +* PCRE2 development files + +Kernel headers are also required when building the optional PPTP, IPoE, or VLAN +monitoring kernel modules. Optional features require their corresponding +development libraries: + +* Net-SNMP for NETSNMP=TRUE +* PostgreSQL client libraries for LOG_PGSQL=TRUE +* Lua for LUA=TRUE or a specific Lua version such as LUA=5.3 + + +Building and installing +======================= + +Use an out-of-tree build directory: + + cmake -S . -B build \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr/local + cmake --build build + sudo cmake --install build + +Useful build options: + +* BUILD_PPTP_DRIVER=TRUE builds the PPTP kernel module. +* BUILD_IPOE_DRIVER=TRUE builds the IPoE kernel module. +* BUILD_VLAN_MON_DRIVER=TRUE builds the VLAN monitoring kernel module. +* BUILD_DRIVER_ONLY=TRUE builds only the selected kernel modules. +* KDIR=/path/to/kernel/build sets the kernel build directory. +* RADIUS=FALSE omits RADIUS support. +* SHAPER=FALSE omits the traffic-shaping module. +* NETSNMP=TRUE builds SNMP support. +* LOG_PGSQL=TRUE builds PostgreSQL logging support. + +For example, to build the IPoE and VLAN monitoring modules for the running +kernel: + + cmake -S . -B build \ + -DBUILD_IPOE_DRIVER=TRUE \ + -DBUILD_VLAN_MON_DRIVER=TRUE \ + -DKDIR="/usr/src/linux-headers-$(uname -r)" + cmake --build build + + +Configuration +============= + +The sample configuration is installed as accel-ppp.conf.dist. See +"man 5 accel-ppp.conf" for the complete configuration reference. + +Enable or disable functionality in the [modules] section. To authenticate from +a pppd-compatible secrets file, enable chap-secrets instead of radius. RADIUS +may remain compiled in; RADIUS=FALSE is only needed when it should be omitted +from the build. Loading both providers does not provide dependable automatic +fallback from RADIUS to chap-secrets because authentication providers are +consulted in module registration order. + +For DM/CoA deployments, configure dae-allowed in the [radius] section to +restrict permitted source addresses. + + +Built-in shaper +=============== + +The shaper supports TBF and HTB queueing disciplines and a clsact policer. +Build it with SHAPER=TRUE (the default), then enable shaper in the +configuration's [modules] section. + +RADIUS rate attributes accept a single rate or separate downstream/upstream +rates. The default attribute is Filter-Id. Values are in Kbit/s unless +Cisco-style attributes are used: + + Filter-Id=1000 + Filter-Id=2000/3000 + +The first example sets both directions to 1000 Kbit/s. The second sets the +downstream rate to 2000 Kbit/s and the upstream rate to 3000 Kbit/s. + +Set a custom rate attribute with attr. The named attribute must exist in the +RADIUS dictionary: + + [shaper] + attr=My-Custom-Rate-Attribute + +Alternatively, use separate attributes for each direction: + + [shaper] + attr-down=PPPD-Downstream-Speed + attr-up=PPPD-Upstream-Speed + +For Cisco-style attributes: + + [shaper] + vendor=Cisco + attr=Cisco-AVPair + +Send input and output attributes to set both directions. In Cisco-style +attributes, input controls upstream traffic and output controls downstream +traffic: + + Cisco-AVPair=lcp:interface-config#1=rate-limit input 2000000 8000 8000 conform-action transmit exceed-action drop + Cisco-AVPair=lcp:interface-config#1=rate-limit output 2000000 8000 8000 conform-action transmit exceed-action drop + +These examples set a 2000 Kbit/s rate and an 8 KB burst in each direction. + + +Burst configuration +------------------- + +For non-Cisco attributes, configure the factors used to calculate bursts from +the rate. down-burst-factor applies to downstream TBF/HTB shaping; +up-burst-factor applies to upstream policing/HTB shaping: + + [shaper] + down-burst-factor=1.0 + up-burst-factor=10.0 + + +Time ranges +----------- + +Time ranges can change rates automatically: + + [shaper] + time-range=1,1:00-3:00 + time-range=2,3:00-5:00 + time-range=3,5:00-7:00 + +Prefix a rate with its range ID and supply multiple RADIUS attributes: + + Filter-Id=1000 + Filter-Id=1,2000 + Filter-Id=2,3000 + Filter-Id=3,4000 + +This sets a default of 1000 Kbit/s and rates of 2000, 3000, and 4000 Kbit/s in +ranges 1, 2, and 3 respectively. + +For Cisco-style time ranges, the access-group value is the range ID: + + Cisco-AVPair=lcp:interface-config#1=rate-limit output access-group 1 1000000 8000 8000 conform-action transmit exceed-action drop + Cisco-AVPair=lcp:interface-config#1=rate-limit input access-group 1 1000000 8000 8000 conform-action transmit exceed-action drop + +When using chap-secrets, an optional fifth column can provide rate information +in the same format. Time ranges are not supported in chap-secrets. + + +SNMP +==== + +Build SNMP support with NETSNMP=TRUE and enable net-snmp in [modules]. ACCEL-PPP +starts as an AgentX subagent by default, so the Net-SNMP master agent must have +AgentX enabled. Consult the Net-SNMP AgentX documentation when configuring the +master agent. To run ACCEL-PPP as the master agent instead: + + [snmp] + master=1 + +Install accel-pppd/extra/net-snmp/ACCEL-PPP-MIB.txt in the local MIB directory. +The file also contains the numerical OIDs used by ACCEL-PPP. Examples: + + # Read statistics and sessions. + snmpwalk -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::accelPPPStat + snmptable -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::sessionsTable + + # Terminate sessions by accounting ID, interface, address, or username. + snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termBySID.0 = 0000000000000001 + snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIfName.0 = ppp2 + snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByIP.0 = 192.0.2.1 + snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::termByUsername.0 = user1 + + # Run a CLI command. + snmpset -m +ACCEL-PPP-MIB -v 2c -c local 127.0.0.1 ACCEL-PPP-MIB::cli.0 = "shaper change all 1024 temp" + + +Encrypted chap-secrets +====================== + +The chap-secrets module supports encrypted passwords through OpenSSL. Set +encrypted=1 in the [chap-secrets] section. Usernames may remain in cleartext or +be transformed through a hash chain configured with username-hash, for example: + + [chap-secrets] + encrypted=1 + username-hash=md5,sha1 + +Hashed usernames must be hexadecimal digest values. Passwords must contain the +NT hash produced by smbencrypt. Encrypted secrets are incompatible with the +auth_chap_md5 module. Hash chains are applied from left to right; for +username-hash=md5,sha1, the binary MD5 result is passed to SHA-1 and the final +digest is stored as hexadecimal. + + +Kernel module warning +===================== + +The out-of-tree PPTP module conflicts with the kernel's ip_gre module. Do not +build ip_gre into the kernel or load it at runtime when using that PPTP module. +Do not mix ACCEL-PPP PPTP connections with poptop's pptpd; stop existing pptpd +sessions before starting ACCEL-PPP. + + +More information +================ + +* Project website: https://accel-ppp.org/ +* Source and issue tracker: https://github.com/accel-ppp/accel-ppp +* Additional RADIUS notes: docs/ +* Email: contact@accel-ppp.org +* ICQ: 337258064 +* Jabber: dima@accel-ppp.org diff --git a/accel-pppd/CMakeLists.txt b/accel-pppd/CMakeLists.txt index cd7186ba..49c2ff61 100644 --- a/accel-pppd/CMakeLists.txt +++ b/accel-pppd/CMakeLists.txt @@ -44,32 +44,18 @@ IF (RADIUS) ADD_SUBDIRECTORY(radius) ENDIF (RADIUS) -# define __free_fn_t in musl INCLUDE (CheckCSourceCompiles) CHECK_C_SOURCE_COMPILES(" -#include <stdlib.h> -#include <search.h> +#include <utmp.h> int main(void) { - __free_fn_t *f; + logwtmp(\"\", \"\", \"\"); return 0; -}" HAVE_FREE_FN_T) -IF (HAVE_FREE_FN_T) - ADD_DEFINITIONS(-DHAVE_FREE_FN_T) -ENDIF (HAVE_FREE_FN_T) +}" HAVE_LOGWTMP) -INCLUDE (CheckCSourceCompiles) -CHECK_C_SOURCE_COMPILES(" -#include <linux/if_arp.h> -#include <net/ethernet.h> -int main(void) -{ - return 0; -}" HAVE_GOOD_IFARP) - -IF (HAVE_GOOD_IFARP) - ADD_DEFINITIONS(-DHAVE_GOOD_IFARP) -ENDIF (HAVE_GOOD_IFARP) +IF (HAVE_LOGWTMP) + ADD_DEFINITIONS(-DHAVE_LOGWTMP) +ENDIF (HAVE_LOGWTMP) ADD_SUBDIRECTORY(triton) @@ -90,12 +76,6 @@ ENDIF (SHAPER) INCLUDE(CheckIncludeFile) CHECK_INCLUDE_FILE("linux/netfilter/ipset/ip_set.h" HAVE_IPSET) -# MUSL does not have printf.h -CHECK_INCLUDE_FILE("printf.h" HAVE_PRINTF_H) -IF (HAVE_PRINTF_H) - ADD_DEFINITIONS(-DHAVE_PRINTF_H) -ENDIF (HAVE_PRINTF_H) - INCLUDE(CheckFunctionExists) CHECK_FUNCTION_EXISTS(setns HAVE_SETNS) @@ -163,9 +143,9 @@ CHECK_FUNCTION_EXISTS(getcontext HAVE_GETCONTEXT) CHECK_FUNCTION_EXISTS(setcontext HAVE_SETCONTEXT) IF (HAVE_GETCONTEXT AND HAVE_SETCONTEXT) - TARGET_LINK_LIBRARIES(accel-pppd triton rt pthread ${crypto_lib} pcre) + TARGET_LINK_LIBRARIES(accel-pppd triton rt pthread ${crypto_lib} pcre2-8) ELSE (HAVE_GETCONTEXT AND HAVE_SETCONTEXT) - TARGET_LINK_LIBRARIES(accel-pppd triton rt pthread ${crypto_lib} pcre ucontext) + TARGET_LINK_LIBRARIES(accel-pppd triton rt pthread ${crypto_lib} pcre2-8 ucontext) ENDIF (HAVE_GETCONTEXT AND HAVE_SETCONTEXT) set_property(TARGET accel-pppd PROPERTY CMAKE_SKIP_BUILD_RPATH FALSE) diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf index abfd1ac9..c9b2017d 100644 --- a/accel-pppd/accel-ppp.conf +++ b/accel-pppd/accel-ppp.conf @@ -6,6 +6,9 @@ log_file connlimit +radius +#chap-secrets + pptp l2tp #sstp @@ -17,9 +20,6 @@ auth_mschap_v1 auth_chap_md5 auth_pap -radius -#chap-secrets - ippool pppd_compat @@ -27,6 +27,7 @@ pppd_compat #shaper #net-snmp #logwtmp +#metrics #ipv6_nd @@ -35,6 +36,7 @@ pppd_compat [core] log-error=/var/log/accel-ppp/core.log +#log-debug=/var/log/accel-ppp/debug.log thread-count=4 [common] @@ -42,11 +44,14 @@ thread-count=4 #single-session-ignore-case=0 #sid-case=upper #sid-source=seq +#seq-file=/var/lib/accel-ppp/seq #max-sessions=1000 #max-starting=0 +#session-timeout=0 #check-ip=0 #nl-snd-buffer=32768 #nl-rcv-buffer=1048576 +#netns-run-dir=/var/run/netns [ppp] verbose=1 @@ -56,7 +61,14 @@ mru=1400 #accomp=deny #pcomp=deny #ccp=0 +#ccp-max-configure=3 #mppe=require +#timeout=3 +#max-configure=10 +#max-failure=10 +#max-terminate=2 +#max-mtu=1500 +#check-ip=0 ipv4=require ipv6=deny ipv6-intf-id=0:0:0:1 @@ -78,7 +90,14 @@ unit-cache=1 [pptp] verbose=1 +#bind=0.0.0.0 +#port=1723 #echo-interval=30 +#echo-failure=3 +#timeout=5 +#mppe=allow +#ppp-max-mtu=1436 +#session-timeout=0 #ip-pool=pptp #ipv6-pool=pptp #ipv6-pool-delegate=pptp @@ -88,16 +107,23 @@ verbose=1 verbose=1 #ac-name=xxx #service-name=yyy +#accept-any-service=0 +#accept-blank-service=0 #pado-delay=0 #pado-delay=0,100:100,200:200,-1:500 called-sid=mac #tr101=1 #padi-limit=0 +#mac-filter=/path/to/mac-filter,allow +#mppe=allow +#session-timeout=0 #ip-pool=pppoe #ipv6-pool=pppoe #ipv6-pool-delegate=pppoe #ifname=pppoe%d +#ifname-in-sid=0 #sid-uppercase=0 +#cookie-timeout=5 #vlan-mon=eth0,10-200 #vlan-timeout=60 #vlan-name=%I.%N @@ -106,6 +132,8 @@ interface=eth0 [l2tp] verbose=1 +#bind=0.0.0.0 +#port=1701 #dictionary=/usr/local/share/accel-ppp/l2tp/dictionary #hello-interval=60 #timeout=60 @@ -116,8 +144,14 @@ verbose=1 #host-name=accel-ppp #dir300_quirk=0 #secret= +#hide-avps=0 #dataseq=allow #reorder-timeout=0 +#use-ephemeral-ports=0 +#ppp-max-mtu=1420 +#mppe=allow +#session-timeout=0 +#avp_permissive=0 #ip-pool=l2tp #ipv6-pool=l2tp #ipv6-pool-delegate=l2tp @@ -125,6 +159,8 @@ verbose=1 [sstp] verbose=1 +#bind=0.0.0.0 +#port=443 #cert-hash-proto=sha1,sha256 #cert-hash-sha1= #cert-hash-sha256= @@ -141,6 +177,10 @@ verbose=1 #http-error=allow #timeout=60 #hello-interval=60 +#ppp-max-mtu=1452 +#sndbuf=0 +#rcvbuf=0 +#session-timeout=0 #ip-pool=sstp #ipv6-pool=sstp #ipv6-pool-delegate=sstp @@ -150,6 +190,7 @@ verbose=1 verbose=1 username=ifname #password=username +#netmask=24 lease-time=600 #renew-time=300 #rebind-time=525 @@ -159,6 +200,7 @@ max-lease-time=3600 #l4-redirect-ipset=l4 #l4-redirect-on-reject=300 #l4-redirect-ip-pool=pool1 +#noauth=0 shared=0 ifcfg=1 mode=L2 @@ -168,7 +210,12 @@ start=dhcpv4 #proxy-arp=0 #nat=0 #proto=100 +#src=192.0.2.1 #relay=10.10.10.10 +#relay-timeout=3 +#relay-retransmit=3 +#agent-remote-id=accel-ppp +#link-selection=0.0.0.0 #vendor=Custom #weight=0 #attr-dhcp-client-ip=DHCP-Client-IP-Address @@ -185,6 +232,7 @@ start=dhcpv4 #attr-l4-redirect-ipset=l4-redirect #lua-file=/etc/accel-ppp.lua #offer-delay=0,100:100,200:200,-1:1000 +#offer-timeout=10 #vlan-mon=eth0,10-200 #vlan-timeout=60 #vlan-name=%I.%N @@ -196,6 +244,8 @@ start=dhcpv4 #soft-terminate=0 #check-mac-change=1 #calling-sid=mac +#ipv6=0 +#check-ip=0 #local-net=192.168.0.0/16 interface=eth0 @@ -209,14 +259,21 @@ interface=eth0 [radius] #dictionary=/usr/local/share/accel-ppp/radius/dictionary +#framed-route-strict=0 nas-identifier=accel-ppp nas-ip-address=127.0.0.1 gw-ip-address=192.168.100.1 server=127.0.0.1,testing123,auth-port=1812,acct-port=1813,req-limit=50,fail-timeout=0,max-fail=10,weight=1 dae-server=127.0.0.1:3799,testing123 +#dae-allowed=127.0.0.1,192.0.2.0/24 +#dae-allowed is generally recommended to restrict DM/CoA sources, but not required. verbose=1 #timeout=3 #max-try=3 +#req-limit=0 +#fail-timeout=0 +#max-fail=10 +#interim-verbose=0 #acct-timeout=120 #acct-delay-time=0 #acct-delay-start=0 @@ -226,7 +283,11 @@ verbose=1 #default-realm= #strip-realm=0 #attr-tunnel-type=My-Tunnel-Type +#sid-in-auth=0 #nas-port-id-in-req=1 +#bind=0.0.0.0 +#require-nas-identification=0 +blast-protection=1 [client-ip-range] 10.0.0.0/8 @@ -236,6 +297,9 @@ gw-ip-address=192.168.0.1 #vendor=Cisco #attr=Cisco-AVPair attr=Framed-Pool +#shuffle=0 +# on reload, sessions whose address left the pools: keep (default) or disconnect +#reload-orphan=keep 192.168.0.2-255 192.168.1.1-255,name=pool1 192.168.2.1-255,name=pool2 @@ -259,6 +323,8 @@ level=3 [log-pgsql] conninfo=user=log +#connect-inteval=5 +#log-query=insert into log (timestamp, username, sessionid, msg) values ($1, $2, $3, $4) log-table=log [pppd-compat] @@ -278,6 +344,10 @@ gw-ip-address=192.168.100.1 [shaper] #attr=Filter-Id +#vendor=Cisco +#attr-down=PPPD-Downstream-Speed +#attr-up=PPPD-Upstream-Speed +#burst-factor=0.1 #down-burst-factor=0.1 #up-burst-factor=1.0 #latency=50 @@ -302,6 +372,8 @@ verbose=1 telnet=127.0.0.1:2000 tcp=127.0.0.1:2001 #password=123 +#prompt=accel-ppp +#history-file=/var/lib/accel-ppp/cli-history #sessions-columns=ifname,username,ip,ip6,ip6-dp,type,state,uptime,uptime-raw,calling-sid,called-sid,sid,comp,inbound-if,service-name,rx-bytes,tx-bytes,rx-bytes-raw,tx-bytes-raw,rx-pkts,tx-pkts,netns,vrf [snmp] @@ -313,11 +385,21 @@ limit=10/min burst=3 timeout=60 +#[metrics] +# Exposes daemon statistics over HTTP. Same numbers as "accel-cmd show stat". +# Enable by adding "metrics" to [modules] above. +#format=prometheus +#address=127.0.0.1:8080 +#allowed_ips=["127.0.0.1/32"] +#read_timeout=5 +#max_clients=64 + [ipv6-pool] #gw-ip6-address=fc00:0:1::1 #vendor= #attr-prefix=Delegated-IPv6-Prefix-Pool #attr-address=Stateful-IPv6-Address-Pool +#reload-orphan=keep fc00:0:1::/48,64 fc00:0:2::/48,64,name=pool1 fc00:0:3::/48,64,name=pool2,next=pool1 @@ -331,9 +413,29 @@ delegate=fc00:3::/36,48,name=pool4,next=pool3 #fc00:1::3 #dnssl=suffix1.local.net #dnssl=suffix2.local.net. +#lifetime=600 [ipv6-dhcp] verbose=1 pref-lifetime=604800 valid-lifetime=2592000 route-via-gw=1 +#aftr-gw=aftr.example.net +#server-id=0:0:0:1 + +[ipv6-nd] +#MaxRtrAdvInterval=600 +#MinRtrAdvInterval=198 +#MaxInitialRtrAdvCount=5 +#MaxInitialRtrAdvInterval=3 +#AdvManagedFlag=0 +#AdvOtherConfigFlag=0 +#AdvLinkMTU=0 +#AdvReachableTime=0 +#AdvRetransTimer=0 +#AdvCurHopLimit=64 +#AdvDefaultLifetime=1800 +#AdvValidLifetime=2592000 +#AdvPreferredLifetime=604800 +#AdvOnLinkFlag=1 +#AdvAutonomousFlag=1 diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5 index 72376c35..bfe97e38 100644 --- a/accel-pppd/accel-ppp.conf.5 +++ b/accel-pppd/accel-ppp.conf.5 @@ -49,6 +49,14 @@ PPPoE discovery stage handling module. .br SSTP controlling connection handling module. .TP +.BI l2tp +.br +L2TPv2 connection handling module. +.TP +.BI ipoe +.br +IPoE connection handling module. +.TP .BI auth_pap PAP authentication module. .TP @@ -65,6 +73,10 @@ Microsoft CHAP (version 2) authentication module. .br RADIUS interaction module. .TP +.BI chap-secrets +.br +Authentication and address assignment from a pppd-compatible chap-secrets file. +.TP .BI ippool .br IPv4 address assigning module. @@ -77,6 +89,26 @@ IPv6 address assigning module. .br IPv6 DHCP module. .TP +.BI ipv6_nd +.br +IPv6 Neighbor Discovery and Router Advertisement module. +.TP +.BI shaper +.br +Traffic shaping and policing module. +.TP +.BI net-snmp +.br +SNMP agent module. It must be built with NETSNMP enabled. +.TP +.BI logwtmp +.br +Module that writes session records to wtmp. +.TP +.BI metrics +.br +HTTP statistics endpoint module. +.TP .BI sigchld Helper module to manage child processes, required by pppd_compat .TP @@ -91,6 +123,9 @@ Configuration of core module .BI "log-error=" path Path to file for core module error logging. .TP +.BI "log-debug=" path +Path to file for core module debug logging. +.TP .BI "thread-count=" n number of working threads, optimal - number of processors/cores .SH [common] @@ -116,7 +151,7 @@ Specifies whether accel-ppp should ignore the case when comparing username withi Specifies in which case generate session identifier (default lower). .TP .BI "sid-source=" urandom|seq -Specifies method assign session id (default urandom). +Specifies method used to assign session IDs (default seq). .br .B urandom Assign session id by random method @@ -135,6 +170,7 @@ Specifies maximum concurrent session attempts which server may processed (defaul .TP .BI "check-ip=" 0|1 Specifies whether accel-ppp should check if IP already assigned to other client interface (default 0). +Check is global (not VRF-aware); with check-ip=1 the same IPv4/IPv6 address will be rejected even if sessions are in different VRFs/netns. With check-ip=0 overlapping addresses can be assigned (useful for isolated VRFs, but take care with overlapping pools). This setting can be overridden by module-specific 'check-ip' options (e.g., in the [ppp] section). .TP .BI "nl-snd-buffer=" n Specifies netlink maximum send buffer size (SO_SNDBUF option) (default 32768). @@ -142,6 +178,9 @@ Specifies netlink maximum send buffer size (SO_SNDBUF option) (default 32768). .BI "nl-rcv-buffer=" n Specifies netlink maximum receive buffer size (SO_RCVBUF option) (default 1048576). .TP +.BI "netns-run-dir=" path +Directory containing named network namespace handles (default /var/run/netns). +.TP .BI "session-timeout=" n Specifies max sessions time in seconds, after this time session will be terminated. .br @@ -183,6 +222,12 @@ Protocol field compression negotiation. .BI "ccp=" n Disable CCP negotiation if this parameter is zero. .TP +.BI "ccp-max-configure=" n +Specifies the maximum number of CCP Configure-Request packets sent without receiving a valid Configure-Ack, Configure-Nak or Configure-Reject before assuming the peer is unable to respond (default 3). +.TP +.BI "timeout=" n +Specifies the timeout, in seconds, used by PPP finite-state machines (default 3). +.TP .BI "mppe=" require|prefer|deny Specifies mppe negotiation preference. .br @@ -198,6 +243,21 @@ Specifies mppe negotiation preference. Default behavior - don't ask client for mppe, but allow it if client wants. Please note that RADIUS may override this option by MS-MPPE-Encryption-Policy attribute. .TP +.BI "max-configure=" n +Specifies the maximum number of LCP/IPCP Configure-Request packets sent without receiving a valid Configure-Ack, Configure-Nak or Configure-Reject before assuming the peer is unable to respond (default 10). +.TP +.BI "max-failure=" n +Specifies the maximum number of LCP/IPCP Configure-Nak returned before starting to send Configure-Reject (default 10). +.TP +.BI "max-terminate=" n +Specifies the maximum number of Terminate-Request packets sent without receiving a Terminate-Ack before assuming the peer has disconnected (default 2). +.TP +.BI "max-mtu=" n +Specifies the absolute maximum MTU value that can be negotiated. +.TP +.BI "check-ip=" 0|1 +Specifies whether to check if the assigned IP address is already in use by another session (overrides [common] check-ip for PPP sessions). +.TP .BI "ipv4=" deny|allow|prefer|require Specify IPv4 (IPCP) negotiation algorithm: .br @@ -521,6 +581,81 @@ If enabled accel-ppp will terminate session when detects change of mac address o .TP .BI "calling-sid=" mac|ip Specifies value of Calling-Station-Id attribute. +.TP +.BI "netmask=" n +Specifies the IPv4 prefix length assigned to IPoE sessions (1 through 32). +.TP +.BI "nat=" 0|1 +Marks IPoE sessions as requiring NAT. +.TP +.BI "noauth=" 0|1 +Authorizes IPoE sessions without consulting a password database. The default is 0. +.TP +.BI "check-ip=" 0|1 +Overrides the common duplicate-address check for IPoE sessions. +.TP +.BI "ipv6=" 0|1 +Enables IPv6 on IPoE interfaces by default. +.TP +.BI "src=" x.x.x.x +Specifies the source address used by the IPoE service. +.TP +.BI "relay-timeout=" n +Specifies the DHCP relay reply timeout in seconds (default 3). +.TP +.BI "relay-retransmit=" n +Specifies the maximum number of DHCP relay retransmissions (default 3). +.TP +.BI "ip-pool=" pool_name +Specifies the default IPv4 address pool. +.TP +.BI "ipv6-pool=" pool_name +Specifies the default IPv6 address pool. +.TP +.BI "ipv6-pool-delegate=" pool_name +Specifies the default delegated IPv6 prefix pool. +.TP +.BI "lua-file=" path +Loads the Lua file that supplies IPoE Lua hooks. Lua support must be built in. +.TP +.BI "vendor=" vendor +Specifies the RADIUS vendor used when resolving the IPoE attribute options below. +.TP +.BI "attr-dhcp-client-ip=" attribute +Specifies the RADIUS attribute containing the DHCP client address. +.TP +.BI "attr-dhcp-router-ip=" attribute +Specifies the RADIUS attribute containing the DHCP router address. +.TP +.BI "attr-dhcp-mask=" attribute +Specifies the RADIUS attribute containing the DHCP subnet mask. +.TP +.BI "attr-dhcp-lease-time=" attribute +Specifies the RADIUS attribute containing the DHCP lease time. +.TP +.BI "attr-dhcp-renew-time=" attribute +Specifies the RADIUS attribute containing the DHCP renewal time. +.TP +.BI "attr-dhcp-rebind-time=" attribute +Specifies the RADIUS attribute containing the DHCP rebinding time. +.TP +.BI "attr-dhcp-opt82=" attribute +Specifies the RADIUS attribute used for the complete DHCP Option 82 value. +.TP +.BI "attr-dhcp-opt82-remote-id=" attribute +Specifies the RADIUS attribute used for the Option 82 remote ID. +.TP +.BI "attr-dhcp-opt82-circuit-id=" attribute +Specifies the RADIUS attribute used for the Option 82 circuit ID. +.TP +.BI "attr-l4-redirect=" attribute +Specifies the RADIUS attribute that enables Layer-4 redirection. +.TP +.BI "attr-l4-redirect-table=" attribute +Specifies the RADIUS attribute containing the redirection routing-table ID. +.TP +.BI "attr-l4-redirect-ipset=" attribute +Specifies the RADIUS attribute containing the redirection ipset name. .SH [dns] .TP .BI "dns1=" x.x.x.x @@ -542,6 +677,9 @@ Specifies IPv6 DNS to be sent to peer. You may specify up to 3 dns options. .TP .BI "dnssl=" name Specify DNS Search List. You may specify multiple dns and dnssl options. +.TP +.BI "lifetime=" n +Specifies the RDNSS and DNSSL lifetime advertised by the ipv6_nd module. .SH [client-ip-range] You have to explicitly specify range of ip address from which clients can connect to server in form: .br @@ -591,6 +729,15 @@ sessions. Default value is 1436. Specifies max sessions time in seconds, after this time session will be terminated. .br This timeout can be redefined with radius attribute Session-Timeout. 0 value means infinite timeout. +.TP +.BI "ip-pool=" pool_name +Specifies the name of the IPv4 pool used by PPTP sessions. +.TP +.BI "ipv6-pool=" pool_name +Specifies the name of the IPv6 pool used by PPTP sessions. +.TP +.BI "ipv6-pool-delegate=" pool_name +Specifies the name of the delegated IPv6 prefix pool used by PPTP sessions. .SH [pppoe] .br Configuration of PPPoE module. @@ -634,9 +781,11 @@ By default vlan-name=%I.%N. .TP .BI "ac-name=" ac-name Specifies AC-Name tag value. If absent tag will not be sent. +The compatibility alias AC-Name=ac-name is also accepted. .TP .BI "service-name=" service-name Specifies Service-Name to respond. If absent any Service-Name is acceptable and client's Service-Name will be sent back. +The compatibility alias Service-Name=service-name is also accepted. .TP .BI "accept-any-service=" n If service-name specified still will answer with service names, but accepts any service name in PADR request. Useful @@ -648,6 +797,7 @@ Useful when needs to allow only Service-Names described in the config and also b .TP .BI "pado-delay=" delay[,delay1:count1[,delay2:count2[,...]]] Specifies delays (also in condition of connection count) to send PADO (ms). +The compatibility alias PADO-Delay=delay is also accepted. Last delay in list may be -1 which means don't accept new connections. List have to be sorted by count key. .TP @@ -691,10 +841,31 @@ as a template, i.e pppoe%d => pppoe0. Specifies max sessions time in seconds, after this time session will be terminated. .br This timeout can be redefined with radius attribute Session-Timeout. 0 value means infinite timeout. +.TP +.BI "ip-pool=" pool_name +Specifies the name of the IPv4 pool to use for allocating client addresses. +.TP +.BI "ipv6-pool=" pool_name +Specifies the name of the IPv6 pool to use for allocating client addresses. +.TP +.BI "ipv6-pool-delegate=" pool_name +Specifies the name of the IPv6 prefix delegation pool to use. +.TP +.BI "ifname-in-sid=" 0|1 +If set to 1, the interface name is included in the Session ID. +.TP +.BI "sid-uppercase=" 0|1 +If set to 1, the Session ID is generated in uppercase. +.TP +.BI "cookie-timeout=" n +Specifies the timeout in seconds for the PPPoE cookie (PADO/PADR stage). .SH [l2tp] .br Configuration of L2TP module. .TP +.BI "dictionary=" path +Specifies an alternate L2TP attribute dictionary. +.TP .BI "bind=" x.x.x.x Specifies IP address to bind. .TP @@ -787,6 +958,21 @@ as a template, i.e l2tp%d => l2tp0. Specifies max sessions time in seconds, after this time session will be terminated. .br This timeout can be redefined with radius attribute Session-Timeout. 0 value means infinite timeout. +.TP +.BI "avp_permissive=" 0|1 +If set to 1, ignore the Mandatory (M) bit in unknown Attribute-Value Pairs (AVPs) instead of terminating the connection. +.TP +.BI "dir300_quirk=" 0|1 +If set to 1, enables a workaround for D-Link DIR-300 routers that send packets with Tunnel ID 0. +.TP +.BI "ip-pool=" pool_name +Specifies the name of the IPv4 pool to use for allocating client addresses. +.TP +.BI "ipv6-pool=" pool_name +Specifies the name of the IPv6 pool to use for allocating client addresses. +.TP +.BI "ipv6-pool-delegate=" pool_name +Specifies the name of the IPv6 prefix delegation pool to use. .SH [sstp] .br Configuration of SSTP module. @@ -822,6 +1008,16 @@ Specifies incoming connection acceptance mode. .br .B proxy - enable PROXY protocol 1 & 2 support. +.br +This is useful when accel-ppp is running behind a load balancer (like HAProxy or Nginx) or a reverse proxy. It allows accel-ppp to receive the original client IP address and port instead of the proxy's IP. The extracted real client IP is then used for: +.br +- \fBconnlimit\fR module checks (limiting connections per source IP). +- \fBclient-ip-range\fR verification. +- \fBCalling-Station-Id\fR attribute in RADIUS and logs. +.br +.TP +.BI "ssl=" 0|1 +Deprecated compatibility option that enables legacy SSL mode. Use accept=ssl instead. .TP .BI "ssl-protocol=" ssl2|ssl3|tls1|tls1.1|tls1.2|tls1.3 Specifies the enabled SSL/TLS protocols supported by OpenSSL library. @@ -842,14 +1038,22 @@ is greater of zero then server ciphers should be preferred over client ciphers. Default is 0. .TP .BI "ssl-pemfile=" pemfile -Specifies a file with the certificate in the PEM format for sstp server. -Certificate is also used to compute initial SHA1 and SHA256 certificate hash. +Specifies a PEM file with the server certificate. Files that contain only the +leaf certificate are still supported for backward compatibility. When the file +includes the full chain, certificates must be sorted starting with the subject's +certificate (actual server certificate), followed by intermediate CA +certificates if applicable, and ending at the highest level (root) CA. The leaf +certificate (first in the file) is used to compute the initial SHA1 and SHA256 +certificate hash. .TP .BI "ssl-keyfile=" keyfile Specifies a file with the secret key in the PEM format for sstp server. If not set, secret key will be loaded from the .BI pemfile -certificate. +parameter. +.TP +.BI "ssl-ca-file=" file +Specifies a CA bundle loaded into the SSTP TLS context. .TP .BI "cert-hash-proto=" sha1,sha256 Specifies hashing methods that can be used to compute the Compound MAC in the Crypto Binding attribute. @@ -894,6 +1098,21 @@ as a template, i.e sstp%d => sstp0. Set the maximum MTU value that can be negotiated for PPP over SSTP sessions. Default value is 1452, maximum is 4087. .TP +.BI "ip-pool=" pool_name +Specifies the name of the IPv4 pool to use for allocating client addresses. +.TP +.BI "ipv6-pool=" pool_name +Specifies the name of the IPv6 pool to use for allocating client addresses. +.TP +.BI "ipv6-pool-delegate=" pool_name +Specifies the name of the IPv6 prefix delegation pool to use. +.TP +.BI "sndbuf=" n +Specifies the TCP send buffer size (SO_SNDBUF) for the SSTP socket. +.TP +.BI "rcvbuf=" n +Specifies the TCP receive buffer size (SO_RCVBUF) for the SSTP socket. +.TP .BI "session-timeout=" n Specifies max sessions time in seconds, after this time session will be terminated. .br @@ -902,6 +1121,9 @@ This timeout can be redefined with radius attribute Session-Timeout. 0 value mea .br Configuration of RADIUS module. .TP +.BI "dictionary=" path +Specifies an alternate RADIUS dictionary. +.TP .BI "nas-identifier=" identifier Specifies value to send to RADIUS server in NAS-Identifier attribute and to be matched in DM/CoA requests. .TP @@ -950,6 +1172,11 @@ Specifies IP address, port to bind and secret for Dynamic Authorization Extensio - device name or VRF to bind the connection. By default, the device name is undefined. .br .TP +.BI "dae-allowed=" ip[,ip/cidr][,ip[/cidr]...] +Specifies allowed source IPv4 addresses or CIDR ranges for DM/CoA requests. +This setting is generally recommended to restrict DM/CoA sources, but it is not required. +.br +.TP .BI "dm_coa_secret=" secret (deprecated, use dae-server instead) Specifies secret to use in DM/CoA communication. .TP @@ -975,6 +1202,18 @@ Timeout to wait response from server (sec) .BI "max-try=" n Specifies number of tries to send Access-Request/Accounting-Request queries. .TP +.BI "req-limit=" n +Specifies the global limit of simultaneous requests per RADIUS server. Zero means unlimited. +.TP +.BI "fail-timeout=" n +Specifies how long, in seconds, an unresponsive RADIUS server remains unavailable. +.TP +.BI "max-fail=" n +Specifies the number of consecutive unanswered requests before a RADIUS server is marked unavailable. +.TP +.BI "fail-time=" n +Deprecated alias for fail-timeout. +.TP .BI "acct-timeout=" n Specifies timeout of accounting interim update. .TP @@ -1004,6 +1243,22 @@ Specifies should accel-ppp generate and send Acct-Session-Id on Access-Request p .TP .BI "nas-port-id-in-req=" 0|1 Specifies should accel-ppp send NAS-Port-Id on Access-Request and Accounting-Request packets (default 1). +.TP +.BI "bind=" x.x.x.x +Specifies the source IP address for outgoing RADIUS packets. +.TP +.BI "require-nas-identification=" 0|1 +If enabled, checks that the NAS-Identifier or NAS-IP-Address in DM/CoA requests matches the server's configuration. +.TP +.BI "blast-protection=" 0|1 +If this option is given and +.B 1 +is specified then radius module will include Message-Authenticator attribute in Access-Request packets. +.TP +.BI "framed-route-strict=" 0|1 +If enabled, only accepts Framed-Route destinations that are valid IPv4 network prefixes +for the specified mask (host bits must be zero). This enforces RFC-style network prefixes. +Default is 0 (disabled). .SH [log] .br Configuration of log and log_file modules. @@ -1017,6 +1272,12 @@ Path to file to write emergency messages. .BI "log-fail-file=" file Path to file to write authentication failed session log. .TP +.BI "log-debug=" file +Path to file to write debug messages. +.TP +.BI "color=" 0|1 +Enables ANSI color sequences in file log output. +.TP .BI "log-tcp=" x.x.x.x:port Send logs to specified host. .TP @@ -1065,6 +1326,14 @@ Configuration of log_pgsql module. .BI "conninfo=" conninfo Conninfo to connect to PostgreSQL server. .TP +.BI "connect-inteval=" n +Specifies the PostgreSQL reconnect interval in seconds (default 5). +The option name intentionally preserves its historical spelling. +.TP +.BI "log-query=" query +Specifies a custom parameterized INSERT query. Parameters $1 through $4 are +timestamp, username, session ID, and message respectively. +.TP .BI "log-table=" table Table to send log messages. Table must contain following field: .br @@ -1079,7 +1348,7 @@ text .br .B msg text -.SH [pppd_compat] +.SH [pppd-compat] .br Configuration of pppd_compat module. .TP @@ -1100,6 +1369,10 @@ Prefix of radattr files (for example /var/run/radattr, resulting files will be / .TP .BI "verbose=" n If specified and greater than zero pppd_module will produce verbose logging. +.TP +.BI "fork-limit=" n +Limits the number of concurrently running compatibility scripts. The default is +twice the number of online processors. .SH [chap-secrets] .br Configuration of chap-secrets module. @@ -1111,7 +1384,7 @@ Specifies address to use as local address of ppp interfaces if chap-secrets is u Specifies alternate chap-secrets file location (default is /etc/ppp/chap-secrets). .TP .BI "encrypted=" 0|1 -Specifies either chap-secrets is encrypted (read README). +Specifies whether chap-secrets is encrypted (see README.md). .TP .BI "username-hash=" hash1[,hash2] Specifies hash chain to calculate username hash. @@ -1126,16 +1399,24 @@ Configuration of ippool module. Specifies single IP address to be used as local address of ppp interfaces. .TP .BI "shuffle=" 1|0 -Specifies whether to shuffle initial address list. +Specifies whether to assign addresses in randomized order instead of sequentially. +.TP +.BI "reload-orphan=" keep|disconnect +Controls what happens on configuration reload to sessions whose assigned address +no longer belongs to any configured pool (a pool was shrunk or removed). With +.B keep +(default) such sessions keep running and their address is simply no longer tracked; +with +.B disconnect +those sessions are terminated. Reload reconciles all live sessions against the new +pools, so growing or renumbering pools no longer requires a restart. .TP .BI "gw=" range -Specifies range of local address of ppp interfaces if form: -.br -.B x.x.x.x/mask[,name=pool_name][,next=next_pool_name] -(for example 10.0.0.0/8) -.br -.B x.x.x.x-y[,name=pool_name][,next=next_pool_name] -(for example 10.0.0.1-254) +Deprecated and ignored. The per-address local gateway has long been overridden at +allocation time by +.B gw-ip-address +(or 0 for IPoE), so this option no longer has any effect. It is still accepted to +avoid breaking existing configuration files. .TP .BI "tunnel=" range Specifies range of remote address of ppp interfaces if form: @@ -1146,16 +1427,85 @@ Specifies range of remote address of ppp interfaces if form: .TP .BI "x.x.x.x/mask[,name=pool_name][,next=next_pool_name] or x.x.x.x-y[,name=pool_name][,next=next_pool_name]" Also specifies range of remote address of ppp interfaces. +.br +You may also omit the "name=" key and use a shorthand pool name after the comma, e.g. +.br +.B 10.0.0.0/24,pool1 .TP .BI "attr=" attribute Specifies which Radius attribute contains pool name. .TP .BI "vendor=" vendor If attribute is vendor-specific then specify vendor name in this option. +.PP +Note: overlapping ranges in different pools are not de-duplicated. If two pools cover the same address, that IP can be allocated from each pool independently. Use non-overlapping ranges (or a single pool with next= chaining) to avoid duplicate assignments. .SH [ipv6-dhcp] .TP +.BI "verbose=" 0|1 +Enables verbose DHCPv6 logging. +.TP +.BI "pref-lifetime=" n +Specifies the preferred address and prefix lifetime in seconds (default 604800). +.TP +.BI "valid-lifetime=" n +Specifies the valid address and prefix lifetime in seconds (default 2592000). +.TP +.BI "route-via-gw=" 0|1 +Controls whether delegated IPv6 routes are installed through the session gateway (default 1). +.TP +.BI "server-id=" x:x:x:x +Specifies the four 16-bit hexadecimal components used as the DHCPv6 server identifier. +.TP .BI "aftr-gw=" name Specifies the AFTR-Name option value to be returned on DHCPv6 replies upon request from the client. +.SH [ipv6-nd] +.br +Configuration of IPv6 Neighbor Discovery and Router Advertisements. +.TP +.BI "MaxRtrAdvInterval=" n +Maximum unsolicited Router Advertisement interval in seconds (default 600). +.TP +.BI "MinRtrAdvInterval=" n +Minimum unsolicited Router Advertisement interval in seconds (default one third of MaxRtrAdvInterval). +.TP +.BI "MaxInitialRtrAdvCount=" n +Maximum number of initial Router Advertisements (default 5). +.TP +.BI "MaxInitialRtrAdvInterval=" n +Maximum interval between initial Router Advertisements in seconds (default 3). +.TP +.BI "AdvManagedFlag=" 0|1 +Sets the Managed Address Configuration flag. By default it follows whether ipv6_dhcp is loaded. +.TP +.BI "AdvOtherConfigFlag=" 0|1 +Sets the Other Configuration flag. By default it follows whether ipv6_dhcp is loaded. +.TP +.BI "AdvLinkMTU=" n +Specifies the MTU advertised in Router Advertisements. Zero omits the MTU option. +.TP +.BI "AdvReachableTime=" n +Specifies the advertised reachable time in milliseconds. +.TP +.BI "AdvRetransTimer=" n +Specifies the advertised retransmission timer in milliseconds. +.TP +.BI "AdvCurHopLimit=" n +Specifies the advertised current hop limit (default 64). +.TP +.BI "AdvDefaultLifetime=" n +Specifies the router lifetime in seconds (default three times MaxRtrAdvInterval). +.TP +.BI "AdvValidLifetime=" n +Specifies the advertised prefix valid lifetime in seconds (default 2592000). +.TP +.BI "AdvPreferredLifetime=" n +Specifies the advertised prefix preferred lifetime in seconds (default 604800). +.TP +.BI "AdvOnLinkFlag=" 0|1 +Sets the advertised prefix on-link flag (default 1). +.TP +.BI "AdvAutonomousFlag=" 0|1 +Sets the autonomous address-configuration flag. By default it is disabled when ipv6_dhcp is loaded and enabled otherwise. .SH [ipv6-pool] .br Configuration of ipv6pool module. @@ -1187,6 +1537,65 @@ Specifies which Radius attribute contains stateful address pool name. .TP .BI "vendor=" vendor If attribute is vendor-specific then specify vendor name in this option. +.TP +.BI "reload-orphan=" keep|disconnect +Same meaning as in the +.B [ip-pool] +section, applied to IPv6 address and delegated-prefix leases on configuration reload. +.PP +Note: each pool range is materialized as a bitmap with one bit per allocatable +prefix, so the number of prefixes in a range (2^(prefix_len-mask)) is capped. Ranges +that would exceed roughly 16.7 million prefixes (prefix_len-mask > 24) are rejected at +parse time with an error rather than allocated. +.SH [metrics] +.br +Exposes daemon statistics over HTTP. Requires the +.B metrics +module to be listed in the +.B [modules] +section. The same numbers shown by +.B "accel-cmd show stat" +are returned for every GET on +.B /metrics +\&. Any other path responds with 404, and any method other than GET +responds with 405. +.TP +.BI "format=" prometheus|json +Selects the body format. Defaults to +.BR prometheus . +.TP +.BI "address=" host:port +IPv4 listen address. Required. Use +.BR 0.0.0.0:8080 +to listen on all interfaces. +.TP +.BI "allowed_ips=" cidr_list +Optional comma-separated list of IPv4 CIDR entries permitted to fetch +metrics. The bracketed form +.RB "\fBallowed_ips = [\(dq" "1.2.3.4/32" "\(dq, \(dq" "5.6.7.0/24" "\(dq]\fR" +and the bare form +.B "1.2.3.4/32,5.6.7.0/24" +are both accepted. A bare address without a prefix length is treated +as +.BR /32 . +When the option is missing or empty, all peers are allowed. Peers +that do not match a CIDR have their connection closed immediately +after +.BR accept (2). +.TP +.BI "read_timeout=" seconds +Maximum time a client may take to deliver a complete HTTP request. +Connections that have not produced a terminating +.B \(dq\er\en\er\en\(dq +within this deadline are closed. Defaults to 5 seconds. Set to +.B 0 +to disable the deadline. +.TP +.BI "max_clients=" n +Maximum number of in-flight HTTP clients. Excess connections are +accepted then immediately closed. Defaults to 64. Set to +.B 0 +to disable the cap. .SH [connlimit] .br This module limits connection rate from single source. @@ -1205,6 +1614,9 @@ This module controls shaper. .BI "attr=" name Specifies which radius attribute contains rate information. Default - Filter-ID. .TP +.BI "vendor=" vendor +Specifies the RADIUS vendor for vendor-specific rate attributes. +.TP .BI "attr-up=" name .TP .BI "attr-down=" name @@ -1224,6 +1636,9 @@ Specifies latency (in milliseconds) parameter of tbf qdisc. .BI "mpu=" n Specifies mpu parameter of tbf qdisc and policer. .TP +.BI "mtu=" n +Specifies the MTU used in shaper calculations. +.TP .BI "r2q=" n Specifies r2q parameter of root htb qdisc. .TP @@ -1233,6 +1648,12 @@ Specifies quantum parameter of htb classes. .BI "moderate-quantum=" 1|0 If fixed quantum is not specified and this option is specified then shaper module will check for quantum value is valid (in range 1000-200000). .TP +.BI "cburst=" n +Specifies the HTB class ceil burst in bytes (default 1534). +.TP +.BI "ifb=" ifname +Specifies the IFB interface used for upstream HTB shaping. Without it, upstream HTB falls back to policing. +.TP .BI "fwmark=" n Specifies the fwmark for traffic that won't be passed through shaper. .TP @@ -1255,6 +1676,9 @@ Due to accel-ppp operates with rates in kilobit basis if you send rates in diffe .TP .BI "rate-limit=" download_speed/upload_speed Specifies, should accel-ppp set default rate-limit for clients. Clients rate-limit will be overwritten by RADIUS filter attributes or chap-secrets rate-limit params. +.TP +.BI "verbose=" 0|1 +Enables verbose shaper logging. .SH [cli] .br Configuration of the command line interface. @@ -1266,13 +1690,19 @@ If \fIn\fR = 2 then cli module will also log passed commands. .TP .BI "tcp=" host:port Defines on which IP address and port the TCP module will listen for incoming -connections. When \fIhost\fR is empty, the TCP module listens on all local -interfaces. It isn't loaded if this option isn't defined. +connections. \fIhost\fR may be an IPv4 or an IPv6 address; IPv6 addresses may +be enclosed in square brackets (e.g. \fI[::1]:2001\fR). When \fIhost\fR is +empty, the TCP module listens on all local interfaces (use \fI[::]:port\fR to +listen on all interfaces over IPv6). It isn't loaded if this option isn't +defined. .TP .BI "telnet=" host:port Defines on which IP address and port the Telnet module will listen for incoming -connections. When \fIhost\fR is empty, the Telnet module listens on all local -interfaces. It isn't loaded if this option isn't defined. +connections. \fIhost\fR may be an IPv4 or an IPv6 address; IPv6 addresses may +be enclosed in square brackets (e.g. \fI[::1]:2000\fR). When \fIhost\fR is +empty, the Telnet module listens on all local interfaces (use \fI[::]:port\fR +to listen on all interfaces over IPv6). It isn't loaded if this option isn't +defined. .TP .BI "password=" passwd Defines the password to be used by the TCP and Telnet modules for @@ -1364,3 +1794,12 @@ command (defaults to - virtual routing and forwarding .br Invalid column names are silently discarded. +.SH [snmp] +.br +Configuration of the optional net-snmp module. +.TP +.BI "master=" 0|1 +Runs as an AgentX subagent when set to 0 (the default), or as the SNMP master agent when set to 1. +.TP +.BI "agent-name=" name +Specifies the AgentX subagent name (default accel-ppp). diff --git a/accel-pppd/auth/CMakeLists.txt b/accel-pppd/auth/CMakeLists.txt index 7a1eb0b0..0270301a 100644 --- a/accel-pppd/auth/CMakeLists.txt +++ b/accel-pppd/auth/CMakeLists.txt @@ -3,7 +3,10 @@ ADD_LIBRARY(auth_chap_md5 SHARED auth_chap_md5.c) ADD_LIBRARY(auth_mschap_v1 SHARED auth_mschap_v1.c) ADD_LIBRARY(auth_mschap_v2 SHARED auth_mschap_v2.c) +TARGET_LINK_LIBRARIES(auth_chap_md5 ${crypto_lib}) +TARGET_LINK_LIBRARIES(auth_mschap_v1 ${crypto_lib}) +TARGET_LINK_LIBRARIES(auth_mschap_v2 ${crypto_lib}) + INSTALL(TARGETS auth_pap auth_chap_md5 auth_mschap_v1 auth_mschap_v2 LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp ) - diff --git a/accel-pppd/auth/auth_chap_md5.c b/accel-pppd/auth/auth_chap_md5.c index 3ff685e6..9cfecb7f 100644 --- a/accel-pppd/auth/auth_chap_md5.c +++ b/accel-pppd/auth/auth_chap_md5.c @@ -7,7 +7,7 @@ #include <stdio.h> #include <arpa/inet.h> -#include "crypto.h" +#include <openssl/md5.h> #include "log.h" #include "events.h" @@ -73,7 +73,6 @@ struct chap_auth_data { struct triton_timer_t interval; int failure; char *name; - char *mschap_error; unsigned int started:1; }; diff --git a/accel-pppd/auth/auth_mschap_v1.c b/accel-pppd/auth/auth_mschap_v1.c index bddaabf5..909bcc5c 100644 --- a/accel-pppd/auth/auth_mschap_v1.c +++ b/accel-pppd/auth/auth_mschap_v1.c @@ -8,7 +8,9 @@ #include <byteswap.h> #include <arpa/inet.h> -#include "crypto.h" +#include <openssl/md4.h> +#include <openssl/sha.h> +#include <openssl/des.h> #include "log.h" #include "ppp.h" diff --git a/accel-pppd/auth/auth_mschap_v2.c b/accel-pppd/auth/auth_mschap_v2.c index 3e944500..440a0995 100644 --- a/accel-pppd/auth/auth_mschap_v2.c +++ b/accel-pppd/auth/auth_mschap_v2.c @@ -8,7 +8,9 @@ #include <byteswap.h> #include <arpa/inet.h> -#include "crypto.h" +#include <openssl/md4.h> +#include <openssl/sha.h> +#include <openssl/des.h> #include "log.h" #include "ppp.h" diff --git a/accel-pppd/cli/cli.c b/accel-pppd/cli/cli.c index 7d440727..6b71cb04 100644 --- a/accel-pppd/cli/cli.c +++ b/accel-pppd/cli/cli.c @@ -63,51 +63,6 @@ void __export cli_register_simple_cmd2( va_end(ap); } -void __export cli_register_regexp_cmd(struct cli_regexp_cmd_t *cmd) -{ - int err; - int erroffset; - const char *errptr; - - if (cmd->exec == NULL) { - log_emerg("cli: impossible to register regexp command" - " without an execution callback function\n"); - _exit(EXIT_FAILURE); - } - if (cmd->pattern == NULL) { - log_emerg("cli: impossible to register regexp command" - " without pattern\n"); - _exit(EXIT_FAILURE); - } - cmd->re = pcre_compile2(cmd->pattern, cmd->options, &err, - &errptr, &erroffset, NULL); - if (!cmd->re) { - log_emerg("cli: failed to compile regexp \"%s\": %s (error %i)" - " at positon %i (unprocessed characters: \"%s\")\n", - cmd->pattern, errptr, err, erroffset, - cmd->pattern + erroffset); - _exit(EXIT_FAILURE); - } - - if (cmd->h_pattern) { - cmd->h_re = pcre_compile2(cmd->h_pattern, cmd->h_options, &err, - &errptr, &erroffset, NULL); - if (!cmd->h_re) { - log_emerg("cli: failed to compile help regexp \"%s\":" - " %s (error %i) at position %i (unprocessed" - " characters: \"%s\")\n", - cmd->h_pattern, errptr, err, erroffset, - cmd->h_pattern + erroffset); - _exit(EXIT_FAILURE); - } - } else { - cmd->h_re = NULL; - cmd->h_pattern = NULL; - } - - list_add_tail(&cmd->entry, ®exp_cmd_list); -} - int __export cli_send(void *client, const char *data) { struct cli_client_t *cln = (struct cli_client_t *)client; @@ -189,13 +144,15 @@ static int cli_process_help_cmd(struct cli_client_t *cln) cmd_found = 1; list_for_each_entry(recmd, ®exp_cmd_list, entry) { + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); if (cmd[0] == '\0' - || pcre_exec(recmd->h_re, NULL, cmd, strlen(cmd), - 0, 0, NULL, 0) >= 0) { + || pcre2_match(recmd->h_re, (PCRE2_SPTR)cmd, strlen(cmd), + 0, 0, match_data, NULL) >= 0) { cmd_found = 1; if (recmd->help) recmd->help(cmd, cln); } + pcre2_match_data_free(match_data); } nb_items = split(cmd, items); @@ -230,14 +187,19 @@ static int cli_process_regexp_cmd(struct cli_client_t *cln, int *err) int res; cmd = skip_space(cmd); - list_for_each_entry(recmd, ®exp_cmd_list, entry) - if (pcre_exec(recmd->re, NULL, cmd, strlen(cmd), - 0, 0, NULL, 0) >= 0) { + list_for_each_entry(recmd, ®exp_cmd_list, entry) { + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + if (pcre2_match(recmd->re, (PCRE2_SPTR)cmd, strlen(cmd), + 0, 0, match_data, NULL) >= 0) { found = 1; res = recmd->exec(cmd, cln); - if (res != CLI_CMD_OK) + if (res != CLI_CMD_OK) { + pcre2_match_data_free(match_data); break; + } } + pcre2_match_data_free(match_data); + } if (found) *err = res; diff --git a/accel-pppd/cli/cli.h b/accel-pppd/cli/cli.h index 6eda5d3f..3d8069b3 100644 --- a/accel-pppd/cli/cli.h +++ b/accel-pppd/cli/cli.h @@ -1,7 +1,8 @@ #ifndef __CLI_H #define __CLI_H -#include <pcre.h> +#define PCRE2_CODE_UNIT_WIDTH 8 +#include <pcre2.h> #include "list.h" @@ -23,11 +24,11 @@ struct cli_simple_cmd_t struct cli_regexp_cmd_t { struct list_head entry; - pcre *re; + pcre2_code *re; const char *pattern; int options; int (*exec)(const char *cmd, void *client); - pcre *h_re; + pcre2_code *h_re; const char *h_pattern; int h_options; int (*help)(const char *cmd, void *client); @@ -42,7 +43,6 @@ void cli_register_simple_cmd2( int hdr_len, ... ); -void cli_register_regexp_cmd(struct cli_regexp_cmd_t *cmd); void cli_show_ses_register(const char *name, const char *desc, void (*print)(struct ap_session *ses, char *buf)); int cli_send(void *client, const char *data); diff --git a/accel-pppd/cli/cli_p.h b/accel-pppd/cli/cli_p.h index 0fcba309..79208e13 100644 --- a/accel-pppd/cli/cli_p.h +++ b/accel-pppd/cli/cli_p.h @@ -2,6 +2,11 @@ #define __CLI_P_H #include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/socket.h> #include "triton.h" @@ -15,6 +20,85 @@ struct cli_client_t int cli_process_cmd(struct cli_client_t *cln); +/* Format peer address (IPv4, IPv6 or IPv4-mapped IPv6) for logging. + * buf must be at least INET6_ADDRSTRLEN bytes long. */ +static inline const char *cli_addr_str(const struct sockaddr_storage *addr, + char *buf, size_t size) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)addr; + const struct sockaddr_in *sin = (const struct sockaddr_in *)addr; + + buf[0] = '\0'; + if (addr->ss_family == AF_INET6) { + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + inet_ntop(AF_INET, &sin6->sin6_addr.s6_addr32[3], buf, size); + else + inet_ntop(AF_INET6, &sin6->sin6_addr, buf, size); + } else + inet_ntop(AF_INET, &sin->sin_addr, buf, size); + + return buf; +} + +/* Parse "host:port", "[host]:port" or ":port" listener specification. + * str is modified in place, *host points into str afterwards (NULL for + * empty host). For unbracketed hosts the last ':' separates the port, + * so bare IPv6 addresses like "::1:2001" are accepted too. + * Returns 0 on success, -1 on invalid format. */ +static inline int cli_parse_hostport(char *str, const char **host, int *port) +{ + char *d; + + if (*str == '[') { + ++str; + d = strchr(str, ']'); + if (!d || d[1] != ':') + return -1; + *d++ = '\0'; + } else { + d = strrchr(str, ':'); + if (!d) + return -1; + } + + *d = '\0'; + *port = atoi(d + 1); + if (*port <= 0) + return -1; + + *host = *str ? str : NULL; + + return 0; +} + +/* Fill sockaddr for binding a CLI listener. host may be an IPv4 or IPv6 + * address; NULL host means any IPv4 address (use "::" for IPv6 wildcard). + * Returns 0 on success, -1 if host is not a valid address. */ +static inline int cli_bind_addr(const char *host, int port, + struct sockaddr_storage *addr, socklen_t *len) +{ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr; + struct sockaddr_in *sin = (struct sockaddr_in *)addr; + + memset(addr, 0, sizeof(*addr)); + + if (host && inet_pton(AF_INET6, host, &sin6->sin6_addr) > 0) { + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(port); + *len = sizeof(*sin6); + } else { + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + if (!host) + sin->sin_addr.s_addr = htonl(INADDR_ANY); + else if (inet_pton(AF_INET, host, &sin->sin_addr) <= 0) + return -1; + *len = sizeof(*sin); + } + + return 0; +} + extern char *conf_cli_passwd; extern char *conf_cli_prompt; diff --git a/accel-pppd/cli/show_sessions.c b/accel-pppd/cli/show_sessions.c index 22f5318a..75649c4a 100644 --- a/accel-pppd/cli/show_sessions.c +++ b/accel-pppd/cli/show_sessions.c @@ -128,9 +128,9 @@ static int show_ses_exec(const char *cmd, char * const *f, int f_cnt, void *cli) struct column_t *match_key = NULL; char *match_pattern = NULL; struct column_t *order_key = NULL; - pcre *re = NULL; - const char *pcre_err; - int pcre_offset; + pcre2_code *re = NULL; + int pcre_err; + PCRE2_SIZE pcre_offset; struct column_t *column; struct col_t *col; struct row_t *row; @@ -169,9 +169,11 @@ static int show_ses_exec(const char *cmd, char * const *f, int f_cnt, void *cli) } if (match_key) { - re = pcre_compile2(match_pattern, 0, NULL, &pcre_err, &pcre_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)match_pattern, PCRE2_ZERO_TERMINATED, 0, &pcre_err, &pcre_offset, NULL); if (!re) { - cli_sendv(cli, "match: %s at %i\r\n", pcre_err, pcre_offset); + PCRE2_UCHAR err_msg[64]; + pcre2_get_error_message(pcre_err, err_msg, sizeof(err_msg)); + cli_sendv(cli, "match: %s at %i\r\n", err_msg, (int)pcre_offset); return CLI_CMD_OK; } } @@ -245,6 +247,7 @@ static int show_ses_exec(const char *cmd, char * const *f, int f_cnt, void *cli) goto oom; cell->col = col; list_add_tail(&cell->entry, &row->cell_list); + cell->buf[0] = 0; col->column->print(ses, cell->buf); n = strlen(cell->buf); if (n > col->width) @@ -262,10 +265,13 @@ static int show_ses_exec(const char *cmd, char * const *f, int f_cnt, void *cli) row = list_entry(t_list.next, typeof(*row), entry); list_del(&row->entry); if (match_key) { - if (pcre_exec(re, NULL, row->match_key, strlen(row->match_key), 0, 0, NULL, 0) < 0) { + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + if (pcre2_match(re, (PCRE2_SPTR)row->match_key, strlen(row->match_key), 0, 0, match_data, NULL) < 0) { free_row(row); + pcre2_match_data_free(match_data); continue; } + pcre2_match_data_free(match_data); } if (order_key) insert_row(&r_list, row); @@ -362,7 +368,7 @@ out: } if (re) - pcre_free(re); + pcre2_code_free(re); return CLI_CMD_OK; diff --git a/accel-pppd/cli/std_cmd.c b/accel-pppd/cli/std_cmd.c index fc073526..1d15a28c 100644 --- a/accel-pppd/cli/std_cmd.c +++ b/accel-pppd/cli/std_cmd.c @@ -5,6 +5,7 @@ #include <signal.h> #include <malloc.h> #include <arpa/inet.h> +#include <inttypes.h> #include "triton.h" #include "events.h" @@ -29,6 +30,9 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, #ifdef MEMDEBUG struct mallinfo mi = mallinfo(); #endif + struct triton_stat_t stat; + + triton_stat_get(&stat); sprintf(statm_fname, "/proc/%i/statm", getpid()); f = fopen(statm_fname, "r"); @@ -38,14 +42,14 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, } clock_gettime(CLOCK_MONOTONIC, &ts); - dt = ts.tv_sec - triton_stat.start_time; + dt = ts.tv_sec - stat.start_time; day = dt / (60 * 60 * 24); dt %= 60 * 60 * 24; hour = dt / (60 * 60); dt %= 60 * 60; cli_sendv(client, "uptime: %i.%02i:%02lu:%02lu\r\n", day, hour, dt / 60, dt % 60); - cli_sendv(client, "cpu: %i%%\r\n", triton_stat.cpu); + cli_sendv(client, "cpu: %i%%\r\n", stat.cpu); #ifdef MEMDEBUG cli_send(client, "memory:\r\n"); cli_sendv(client, " rss/virt: %lu/%lu kB\r\n", vmrss * page_size_kb, vmsize * page_size_kb); @@ -57,23 +61,29 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, cli_sendv(client, "mem(rss/virt): %lu/%lu kB\r\n", vmrss * page_size_kb, vmsize * page_size_kb); #endif cli_send(client, "core:\r\n"); - cli_sendv(client, " mempool_allocated: %u\r\n", triton_stat.mempool_allocated); - cli_sendv(client, " mempool_available: %u\r\n", triton_stat.mempool_available); - cli_sendv(client, " thread_count: %u\r\n", triton_stat.thread_count); - cli_sendv(client, " thread_active: %u\r\n", triton_stat.thread_active); - cli_sendv(client, " context_count: %u\r\n", triton_stat.context_count); - cli_sendv(client, " context_sleeping: %u\r\n", triton_stat.context_sleeping); - cli_sendv(client, " context_pending: %u\r\n", triton_stat.context_pending); - cli_sendv(client, " md_handler_count: %u\r\n", triton_stat.md_handler_count); - cli_sendv(client, " md_handler_pending: %u\r\n", triton_stat.md_handler_pending); - cli_sendv(client, " timer_count: %u\r\n", triton_stat.timer_count); - cli_sendv(client, " timer_pending: %u\r\n", triton_stat.timer_pending); + cli_sendv(client, " mempool_allocated: %" PRIu64 "\r\n", stat.mempool_allocated); + cli_sendv(client, " mempool_available: %" PRIu64 "\r\n", stat.mempool_available); + cli_sendv(client, " thread_count: %u\r\n", stat.thread_count); + cli_sendv(client, " thread_active: %u\r\n", stat.thread_active); + cli_sendv(client, " context_count: %u\r\n", stat.context_count); + cli_sendv(client, " context_sleeping: %u\r\n", stat.context_sleeping); + cli_sendv(client, " context_pending: %u\r\n", stat.context_pending); + cli_sendv(client, " md_handler_count: %u\r\n", stat.md_handler_count); + cli_sendv(client, " md_handler_pending: %u\r\n", stat.md_handler_pending); + cli_sendv(client, " timer_count: %u\r\n", stat.timer_count); + cli_sendv(client, " timer_pending: %u\r\n", stat.timer_pending); //=========== - cli_send(client, "sessions:\r\n"); - cli_sendv(client, " starting: %u\r\n", ap_session_stat.starting); - cli_sendv(client, " active: %u\r\n", ap_session_stat.active); - cli_sendv(client, " finishing: %u\r\n", ap_session_stat.finishing); + { + struct ap_session_stat ses_stat; + + ap_session_stat_get(&ses_stat); + + cli_send(client, "sessions:\r\n"); + cli_sendv(client, " starting: %u\r\n", ses_stat.starting); + cli_sendv(client, " active: %u\r\n", ses_stat.active); + cli_sendv(client, " finishing: %u\r\n", ses_stat.finishing); + } return CLI_CMD_OK; } @@ -123,9 +133,9 @@ static int terminate_exec1(char * const *f, int f_cnt, void *cli) { struct ap_session *ses; int hard = 0; - pcre *re; - const char *pcre_err; - int pcre_offset; + pcre2_code *re; + int pcre_err; + PCRE2_SIZE pcre_offset; if (f_cnt == 5) { if (!strcmp(f[4], "hard")) @@ -135,9 +145,11 @@ static int terminate_exec1(char * const *f, int f_cnt, void *cli) } else if (f_cnt != 4) return CLI_CMD_SYNTAX; - re = pcre_compile2(f[3], 0, NULL, &pcre_err, &pcre_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)f[3], PCRE2_ZERO_TERMINATED, 0, &pcre_err, &pcre_offset, NULL); if (!re) { - cli_sendv(cli, "match: %s at %i\r\n", pcre_err, pcre_offset); + PCRE2_UCHAR err_msg[64]; + pcre2_get_error_message(pcre_err, err_msg, sizeof(err_msg)); + cli_sendv(cli, "match: %s at %i\r\n", err_msg, (int)pcre_offset); return CLI_CMD_OK; } @@ -145,8 +157,12 @@ static int terminate_exec1(char * const *f, int f_cnt, void *cli) list_for_each_entry(ses, &ses_list, entry) { if (!ses->username) continue; - if (pcre_exec(re, NULL, ses->username, strlen(ses->username), 0, 0, NULL, 0) < 0) + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + if (pcre2_match(re, (PCRE2_SPTR)ses->username, strlen(ses->username), 0, 0, match_data, NULL) < 0) { + pcre2_match_data_free(match_data); continue; + } + pcre2_match_data_free(match_data); if (hard) triton_context_call(ses->ctrl->ctx, (triton_event_func)__terminate_hard, ses); else @@ -154,7 +170,7 @@ static int terminate_exec1(char * const *f, int f_cnt, void *cli) } pthread_rwlock_unlock(&ses_lock); - pcre_free(re); + pcre2_code_free(re); return CLI_CMD_OK; } @@ -324,26 +340,41 @@ static int shutdown_exec(const char *cmd, char * const *f, int f_cnt, void *cli) } //========================== -static int conf_reload_res; -static struct triton_context_t *conf_reload_ctx; -static void conf_reload_notify(int r) +struct conf_reload_req { + struct triton_context_t *ctx; + int res; +}; +static void conf_reload_notify(int r, void *arg) { + struct conf_reload_req *req = arg; + if (!r) triton_event_fire(EV_CONFIG_RELOAD, NULL); - conf_reload_res = r; - triton_context_wakeup(conf_reload_ctx); + req->res = r; + triton_context_wakeup(req->ctx); } static int reload_exec(const char *cmd, char * const *f, int f_cnt, void *cli) { - if (f_cnt == 1) { - conf_reload_ctx = triton_context_self(); - triton_conf_reload(conf_reload_notify); - triton_context_schedule(); - if (conf_reload_res) - cli_send(cli, "failed\r\n"); - return CLI_CMD_OK; - } else + struct conf_reload_req *req; + + if (f_cnt != 1) return CLI_CMD_SYNTAX; + + /* heap-allocated: triton_context_schedule() can migrate this + * context to another worker thread's stack before notify runs */ + req = _malloc(sizeof(*req)); + req->ctx = triton_context_self(); + + if (triton_conf_reload(conf_reload_notify, req)) { + _free(req); + cli_send(cli, "reload is already in progress\r\n"); + return CLI_CMD_OK; + } + triton_context_schedule(); + if (req->res) + cli_send(cli, "failed\r\n"); + _free(req); + return CLI_CMD_OK; } static void reload_help(char * const *fields, int fields_cnt, void *client) diff --git a/accel-pppd/cli/tcp.c b/accel-pppd/cli/tcp.c index 8952661a..beba16ca 100644 --- a/accel-pppd/cli/tcp.c +++ b/accel-pppd/cli/tcp.c @@ -24,7 +24,7 @@ struct tcp_client_t { struct cli_client_t cli_client; struct list_head entry; struct triton_md_handler_t hnd; - struct sockaddr_in addr; + struct sockaddr_storage addr; struct list_head xmit_queue; struct buffer_t *xmit_buf; uint8_t *cmdline; @@ -174,8 +174,10 @@ static int cln_read(struct triton_md_handler_t *h) goto disconn_hard; cln->auth = 1; } else { - if (conf_verbose == 2) - log_info2("cli: %s: %s\n", inet_ntoa(cln->addr.sin_addr), cln->cmdline); + if (conf_verbose == 2) { + char buf[INET6_ADDRSTRLEN]; + log_info2("cli: %s: %s\n", cli_addr_str(&cln->addr, buf, sizeof(buf)), cln->cmdline); + } cli_process_cmd(&cln->cli_client); } @@ -248,12 +250,14 @@ disconn: static int serv_read(struct triton_md_handler_t *h) { - struct sockaddr_in addr; - socklen_t size = sizeof(addr); + struct sockaddr_storage addr; + socklen_t size; int sock; struct tcp_client_t *conn; + char buf[INET6_ADDRSTRLEN]; while(1) { + size = sizeof(addr); sock = accept(h->fd, (struct sockaddr *)&addr, &size); if (sock < 0) { if (errno == EAGAIN) @@ -263,7 +267,7 @@ static int serv_read(struct triton_md_handler_t *h) } if (conf_verbose) - log_info2("cli: tcp: new connection from %s\n", inet_ntoa(addr.sin_addr)); + log_info2("cli: tcp: new connection from %s\n", cli_addr_str(&addr, buf, sizeof(buf))); if (fcntl(sock, F_SETFL, O_NONBLOCK)) { log_error("cli: tcp: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno)); @@ -320,9 +324,16 @@ static struct triton_md_handler_t serv_hnd = { static void start_server(const char *host, int port) { - struct sockaddr_in addr; + struct sockaddr_storage addr; + socklen_t addrlen; + int f = 1; + + if (cli_bind_addr(host, port, &addr, &addrlen) < 0) { + log_emerg("cli: tcp: invalid address '%s'\n", host); + return; + } - serv_hnd.fd = socket(PF_INET, SOCK_STREAM, 0); + serv_hnd.fd = socket(addr.ss_family, SOCK_STREAM, 0); if (serv_hnd.fd < 0) { log_emerg("cli: tcp: failed to create server socket: %s\n", strerror(errno)); return; @@ -330,16 +341,8 @@ static void start_server(const char *host, int port) fcntl(serv_hnd.fd, F_SETFD, fcntl(serv_hnd.fd, F_GETFD) | FD_CLOEXEC); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - if (host) - addr.sin_addr.s_addr = inet_addr(host); - else - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - setsockopt(serv_hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv_hnd.fd, 4); - if (bind (serv_hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { + setsockopt(serv_hnd.fd, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f)); + if (bind (serv_hnd.fd, (struct sockaddr *) &addr, addrlen) < 0) { log_emerg("cli: tcp: failed to bind socket: %s\n", strerror(errno)); close(serv_hnd.fd); return; @@ -378,7 +381,8 @@ static void load_config(void) static void init(void) { const char *opt; - char *host, *d; + const char *addr; + char *host; int port; opt = conf_get_opt("cli", "tcp"); @@ -386,20 +390,14 @@ static void init(void) return; host = strdup(opt); - d = strstr(host, ":"); - if (!d) - goto err_fmt; - - *d = 0; - port = atoi(d + 1); - if (port <= 0) + if (cli_parse_hostport(host, &addr, &port) < 0) goto err_fmt; load_config(); temp_buf = malloc(RECV_BUF_SIZE); - start_server(host, port); + start_server(addr, port); triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config); diff --git a/accel-pppd/cli/telnet.c b/accel-pppd/cli/telnet.c index 7d5009c2..88a9d8b0 100644 --- a/accel-pppd/cli/telnet.c +++ b/accel-pppd/cli/telnet.c @@ -37,7 +37,7 @@ struct telnet_client_t { struct cli_client_t cli_client; struct list_head entry; struct triton_md_handler_t hnd; - struct sockaddr_in addr; + struct sockaddr_storage addr; struct list_head xmit_queue; struct buffer_t *xmit_buf; int xmit_pos; @@ -305,8 +305,10 @@ static int telnet_input_char(struct telnet_client_t *cln, uint8_t c) list_add(&b->entry, cln->history.next); cln->history_pos = cln->history.next; - if (conf_verbose == 2) - log_info2("cli: %s: %s\n", inet_ntoa(cln->addr.sin_addr), cln->cmdline); + if (conf_verbose == 2) { + char abuf[INET6_ADDRSTRLEN]; + log_info2("cli: %s: %s\n", cli_addr_str(&cln->addr, abuf, sizeof(abuf)), cln->cmdline); + } if (cli_process_cmd(&cln->cli_client)) return -1; @@ -556,13 +558,15 @@ disconn: static int serv_read(struct triton_md_handler_t *h) { - struct sockaddr_in addr; - socklen_t size = sizeof(addr); + struct sockaddr_storage addr; + socklen_t size; int sock; struct telnet_client_t *conn; struct buffer_t *b, *b2; + char abuf[INET6_ADDRSTRLEN]; while(1) { + size = sizeof(addr); sock = accept(h->fd, (struct sockaddr *)&addr, &size); if (sock < 0) { if (errno == EAGAIN) @@ -572,7 +576,7 @@ static int serv_read(struct triton_md_handler_t *h) } if (conf_verbose) - log_info2("cli: telnet: new connection from %s\n", inet_ntoa(addr.sin_addr)); + log_info2("cli: telnet: new connection from %s\n", cli_addr_str(&addr, abuf, sizeof(abuf))); fcntl(sock, F_SETFL, O_NONBLOCK); fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC); @@ -657,9 +661,16 @@ static struct triton_md_handler_t serv_hnd = { static void start_server(const char *host, int port) { - struct sockaddr_in addr; + struct sockaddr_storage addr; + socklen_t addrlen; + int f = 1; + + if (cli_bind_addr(host, port, &addr, &addrlen) < 0) { + log_emerg("cli: telnet: invalid address '%s'\n", host); + return; + } - serv_hnd.fd = socket(PF_INET, SOCK_STREAM, 0); + serv_hnd.fd = socket(addr.ss_family, SOCK_STREAM, 0); if (serv_hnd.fd < 0) { log_emerg("cli: telnet: failed to create server socket: %s\n", strerror(errno)); return; @@ -667,16 +678,8 @@ static void start_server(const char *host, int port) fcntl(serv_hnd.fd, F_SETFD, fcntl(serv_hnd.fd, F_GETFD) | FD_CLOEXEC); - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - if (host) - addr.sin_addr.s_addr = inet_addr(host); - else - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - setsockopt(serv_hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv_hnd.fd, 4); - if (bind (serv_hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { + setsockopt(serv_hnd.fd, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f)); + if (bind (serv_hnd.fd, (struct sockaddr *) &addr, addrlen) < 0) { log_emerg("cli: telnet: failed to bind socket: %s\n", strerror(errno)); close(serv_hnd.fd); return; @@ -755,7 +758,8 @@ static void load_config(void) static void init(void) { const char *opt; - char *host, *d; + const char *addr; + char *host; int port; opt = conf_get_opt("cli", "telnet"); @@ -763,13 +767,7 @@ static void init(void) return; host = strdup(opt); - d = strstr(host, ":"); - if (!d) - goto err_fmt; - - *d = 0; - port = atoi(d + 1); - if (port <= 0) + if (cli_parse_hostport(host, &addr, &port) < 0) goto err_fmt; opt = conf_get_opt("cli", "history-file"); @@ -783,7 +781,7 @@ static void init(void) load_history_file(); - start_server(host, port); + start_server(addr, port); atexit(save_history_file); diff --git a/accel-pppd/ctrl/ipoe/arp.c b/accel-pppd/ctrl/ipoe/arp.c index ef9d3859..a6ca5b13 100644 --- a/accel-pppd/ctrl/ipoe/arp.c +++ b/accel-pppd/ctrl/ipoe/arp.c @@ -13,10 +13,8 @@ #include <netinet/ip.h> #include <sys/socket.h> #include <sys/ioctl.h> -#ifdef HAVE_GOOD_IFARP -#include <linux/if_arp.h> -#endif -#include <linux/if_packet.h> +#include <net/if_arp.h> +#include <netpacket/packet.h> #include "list.h" #include "triton.h" diff --git a/accel-pppd/ctrl/ipoe/dhcpv4.c b/accel-pppd/ctrl/ipoe/dhcpv4.c index 466dfee6..d80a80f3 100644 --- a/accel-pppd/ctrl/ipoe/dhcpv4.c +++ b/accel-pppd/ctrl/ipoe/dhcpv4.c @@ -161,7 +161,7 @@ struct dhcpv4_serv *dhcpv4_create(struct triton_context_t *ctx, const char *ifna goto out_err; } - if (bind(sock, &addr, sizeof(addr))) { + if (bind(sock, (struct sockaddr*)&addr, sizeof(addr))) { log_error("bind: %s\n", strerror(errno)); goto out_err; } @@ -356,9 +356,9 @@ static int dhcpv4_parse_packet(struct dhcpv4_packet *pack, int len) else if (opt->type == 62) pack->client_id = opt; else if (opt->type == 50) - pack->request_ip = *(uint32_t *)opt->data; + memcpy(&pack->request_ip, opt->data, 4); else if (opt->type == 54) - pack->server_id = *(uint32_t *)opt->data; + memcpy(&pack->server_id, opt->data, 4); } if (pack->msg_type == 0 || pack->msg_type > 8) @@ -1012,12 +1012,12 @@ struct dhcpv4_relay *dhcpv4_relay_create(const char *_addr, in_addr_t giaddr, st if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &f, sizeof(f))) log_error("dhcpv4: setsockopt(SO_REUSEADDR): %s\n", strerror(errno)); - if (bind(sock, &laddr, sizeof(laddr))) { + if (bind(sock, (struct sockaddr*)&laddr, sizeof(laddr))) { log_error("dhcpv4: relay: %s: bind: %s\n", _addr, strerror(errno)); goto out_err_unlock; } - if (connect(sock, &raddr, sizeof(raddr))) { + if (connect(sock, (struct sockaddr*)&raddr, sizeof(raddr))) { log_error("dhcpv4: relay: %s: connect: %s\n", _addr, strerror(errno)); goto out_err_unlock; } diff --git a/accel-pppd/ctrl/ipoe/dhcpv4_options.c b/accel-pppd/ctrl/ipoe/dhcpv4_options.c index b5f2b3bf..bffcfa5c 100644 --- a/accel-pppd/ctrl/ipoe/dhcpv4_options.c +++ b/accel-pppd/ctrl/ipoe/dhcpv4_options.c @@ -46,7 +46,7 @@ static struct known_option options[] = { { 26, 2, 2, 2, "MTU", print_int }, { 28, 4, 4, 4, "Broadcast", print_ip }, { 33, 8, 255, 8, "Route", print_route }, - { 42, 4, 4, 4, "NTP", print_ip }, + { 42, 4, 255, 4, "NTP", print_ip }, { 43, 1, 255, 1, "Vendor-Specific", print_hex }, { 50, 4, 4, 4, "Request-IP", print_ip }, { 51, 4, 4, 4, "Lease-Time", print_uint }, @@ -113,18 +113,28 @@ void dhcpv4_print_options(struct dhcpv4_packet *pack, void (*print)(const char * static void print_int(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...)) { - if (opt->len == 2) - print("%i", ntohs(*(int16_t *)(opt->data))); - else - print("%i", ntohl(*(int32_t *)(opt->data))); + if (opt->len == 2) { + int16_t val; + memcpy(&val, opt->data, sizeof(val)); + print("%i", ntohs(val)); + } else { + int32_t val; + memcpy(&val, opt->data, sizeof(val)); + print("%i", ntohl(val)); + } } static void print_uint(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...)) { - if (opt->len == 2) - print("%u", ntohs(*(uint16_t *)(opt->data))); - else - print("%u", ntohl(*(uint32_t *)(opt->data))); + if (opt->len == 2) { + uint16_t val; + memcpy(&val, opt->data, sizeof(val)); + print("%u", ntohs(val)); + } else { + uint32_t val; + memcpy(&val, opt->data, sizeof(val)); + print("%u", ntohl(val)); + } } static void print_ip(const struct dhcpv4_option *opt, int elem_size, void (*print)(const char *fmt, ...)) @@ -133,7 +143,8 @@ static void print_ip(const struct dhcpv4_option *opt, int elem_size, void (*prin uint32_t ip; for (i = 0; i < n; i++) { - ip = ntohl(*(uint32_t *)(opt->data + i*elem_size)); + memcpy(&ip, opt->data + i*elem_size, sizeof(ip)); + ip = ntohl(ip); if (i) print(","); @@ -170,8 +181,10 @@ static void print_route(const struct dhcpv4_option *opt, int elem_size, void (*p uint32_t ip, gw; for (i = 0; i < n; i++) { - ip = ntohl(*(uint32_t *)(opt->data + i*8)); - gw = ntohl(*(uint32_t *)(opt->data + i*8 + 4)); + memcpy(&ip, opt->data + i*8, sizeof(ip)); + memcpy(&gw, opt->data + i*8 + 4, sizeof(gw)); + ip = ntohl(ip); + gw = ntohl(gw); if (i) print(","); diff --git a/accel-pppd/ctrl/ipoe/ipoe.c b/accel-pppd/ctrl/ipoe/ipoe.c index 95ff8568..18e9228d 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.c +++ b/accel-pppd/ctrl/ipoe/ipoe.c @@ -14,13 +14,9 @@ #include <netinet/ip.h> #include <sys/socket.h> #include <sys/ioctl.h> -#include <linux/if.h> -#ifdef HAVE_GOOD_IFARP -#include <linux/if_arp.h> -#endif -#include <linux/route.h> - -#include <pcre.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <net/route.h> #include "events.h" #include "list.h" @@ -56,7 +52,7 @@ #define SESSION_TERMINATED "Session was terminated" struct iplink_arg { - pcre *re; + pcre2_code *re; const char *opt; long *arg1; }; @@ -184,9 +180,7 @@ static int conf_check_mac_change; static int conf_soft_terminate; static int conf_calling_sid = SID_MAC; -static unsigned int stat_starting; -static unsigned int stat_active; -static unsigned int stat_delayed_offer; +static struct ipoe_stat_t ipoe_stat; static mempool_t ses_pool; static mempool_t disc_item_pool; @@ -229,6 +223,39 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc static void __terminate(struct ap_session *ses); static void ipoe_ipv6_disable(struct ipoe_serv *serv); +void __export ipoe_stat_get(struct ipoe_stat_t *stat) +{ + stat->starting = __atomic_load_n(&ipoe_stat.starting, __ATOMIC_RELAXED); + stat->active = __atomic_load_n(&ipoe_stat.active, __ATOMIC_RELAXED); + stat->delayed_offer = __atomic_load_n(&ipoe_stat.delayed_offer, __ATOMIC_RELAXED); +} + +unsigned int __export ipoe_stat_starting(void) +{ + return __atomic_load_n(&ipoe_stat.starting, __ATOMIC_RELAXED); +} + +unsigned int __export ipoe_stat_active(void) +{ + return __atomic_load_n(&ipoe_stat.active, __ATOMIC_RELAXED); +} + +static void ipoe_stat_inc(unsigned int *stat) +{ + __atomic_add_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void ipoe_stat_dec(unsigned int *stat) +{ + __atomic_sub_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void ipoe_stat_move(unsigned int *from, unsigned int *to) +{ + ipoe_stat_dec(from); + ipoe_stat_inc(to); +} + static void ipoe_ctx_switch(struct triton_context_t *ctx, void *arg) { if (arg) { @@ -745,7 +772,7 @@ static void ipoe_session_start(struct ipoe_session *ses) } } - __sync_add_and_fetch(&stat_starting, 1); + ipoe_stat_inc(&ipoe_stat.starting); assert(!ses->ses.username); @@ -756,6 +783,10 @@ static void ipoe_session_start(struct ipoe_session *ses) return; } + /* take ownership now so the string is freed by ipoe_session_free() + * even if the session terminates before auth_result() consumes it */ + ses->username = username; + ses->ses.unit_idx = ses->serv->ifindex; triton_event_fire(EV_CTRL_STARTING, &ses->ses); @@ -766,9 +797,9 @@ static void ipoe_session_start(struct ipoe_session *ses) if (ses->serv->opt_shared && ipoe_create_interface(ses)) return; - if (conf_noauth) + if (conf_noauth) { r = PWDB_SUCCESS; - else { + } else { #ifdef RADIUS if (radius_loaded) { ses->radius.send_access_request = ipoe_rad_send_auth_request; @@ -785,7 +816,6 @@ static void ipoe_session_start(struct ipoe_session *ses) } else pass = username; - ses->username = username; r = pwdb_check(&ses->ses, (pwdb_callback)auth_result, ses, username, PPP_PAP, pass); if (r == PWDB_WAIT) @@ -1023,9 +1053,9 @@ static void __ipoe_session_activate(struct ipoe_session *ses) in_addr_t gw; iproute_get(ses->router, &gw, NULL); if (gw) - iproute_add(0, ses->siaddr, ses->yiaddr, gw, conf_proto, 32); + iproute_add(0, ses->siaddr, ses->yiaddr, gw, conf_proto, 32, NULL); else - iproute_add(0, ses->siaddr, ses->router, gw, conf_proto, 32); + iproute_add(0, ses->siaddr, ses->router, gw, conf_proto, 32, NULL); }*/ if (serv->opt_mode == MODE_L3) @@ -1061,17 +1091,16 @@ static void __ipoe_session_activate(struct ipoe_session *ses) } } - __sync_sub_and_fetch(&stat_starting, 1); - __sync_add_and_fetch(&stat_active, 1); + ipoe_stat_move(&ipoe_stat.starting, &ipoe_stat.active); ses->started = 1; ap_session_activate(&ses->ses); if (ses->ifindex == -1 && !serv->opt_ifcfg) { if (!serv->opt_ip_unnumbered) - iproute_add(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0); + iproute_add(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0, NULL); else - iproute_add(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0); + iproute_add(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0, NULL); } if (ses->l4_redirect) @@ -1172,7 +1201,7 @@ static void ipoe_session_started(struct ap_session *s) if (ses->ses.ipv4->peer_addr != ses->yiaddr) //ipaddr_add_peer(ses->ses.ifindex, ses->router, ses->yiaddr); // breaks quagga - iproute_add(ses->ses.ifindex, ses->router, ses->yiaddr, 0, conf_proto, 32, 0); + iproute_add(ses->ses.ifindex, ses->router, ses->yiaddr, 0, conf_proto, 32, 0, NULL); if (ses->ifindex != -1 && ses->xid) { ses->dhcpv4 = dhcpv4_create(ses->ctrl.ctx, ses->ses.ifname, ""); @@ -1187,9 +1216,9 @@ static void ipoe_session_started(struct ap_session *s) static void ipoe_session_free(struct ipoe_session *ses) { if (ses->started) - __sync_sub_and_fetch(&stat_active, 1); + ipoe_stat_dec(&ipoe_stat.active); else - __sync_sub_and_fetch(&stat_starting, 1); + ipoe_stat_dec(&ipoe_stat.starting); if (ses->timer.tpd) triton_timer_del(&ses->timer); @@ -1215,6 +1244,9 @@ static void ipoe_session_free(struct ipoe_session *ses) if (ses->l4_redirect_ipset) _free(ses->l4_redirect_ipset); + if (ses->username) + _free(ses->username); + triton_context_unregister(&ses->ctx); if (ses->data) @@ -1256,9 +1288,9 @@ static void ipoe_session_finished(struct ap_session *s) } else if (ses->started) { if (!serv->opt_ifcfg) { if (!serv->opt_ip_unnumbered) - iproute_del(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0); + iproute_del(serv->ifindex, ses->router, ses->yiaddr, 0, conf_proto, ses->mask, 0, NULL); else - iproute_del(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0); + iproute_del(serv->ifindex, serv->opt_src ?: ses->router, ses->yiaddr, 0, conf_proto, 32, 0, NULL); } } @@ -1365,10 +1397,10 @@ static struct ipoe_session *ipoe_session_create_dhcpv4(struct ipoe_serv *serv, s if (ap_shutdown) return NULL; - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) return NULL; - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) return NULL; ses = ipoe_session_alloc(serv->ifname); @@ -1635,7 +1667,7 @@ static void ipoe_serv_disc_timer(struct triton_timer_t *t) list_del(&d->entry); mempool_free(d); - __sync_sub_and_fetch(&stat_delayed_offer, 1); + ipoe_stat_dec(&ipoe_stat.delayed_offer); } while (!list_empty(&serv->arp_list)) { @@ -1654,7 +1686,7 @@ static void ipoe_serv_disc_timer(struct triton_timer_t *t) list_del(&d->entry); mempool_free(d); - __sync_sub_and_fetch(&stat_delayed_offer, 1); + ipoe_stat_dec(&ipoe_stat.delayed_offer); } if (list_empty(&serv->disc_list) && list_empty(&serv->arp_list)) @@ -1675,7 +1707,7 @@ static void ipoe_serv_add_disc_arp(struct ipoe_serv *serv, struct _arphdr *arph, if (!d) return; - __sync_add_and_fetch(&stat_delayed_offer, 1); + ipoe_stat_inc(&ipoe_stat.delayed_offer); memcpy(&d->arph, arph, sizeof(*arph)); clock_gettime(CLOCK_MONOTONIC, &d->ts); @@ -1695,7 +1727,7 @@ static void ipoe_serv_add_disc(struct ipoe_serv *serv, struct dhcpv4_packet *pac if (!d) return; - __sync_add_and_fetch(&stat_delayed_offer, 1); + ipoe_stat_inc(&ipoe_stat.delayed_offer); dhcpv4_packet_ref(pack); d->pack = pack; @@ -1724,7 +1756,7 @@ static int ipoe_serv_check_disc(struct ipoe_serv *serv, struct dhcpv4_packet *pa dhcpv4_packet_free(d->pack); mempool_free(d); - __sync_sub_and_fetch(&stat_delayed_offer, 1); + ipoe_stat_dec(&ipoe_stat.delayed_offer); return 1; } @@ -1872,7 +1904,7 @@ static void __ipoe_recv_dhcpv4(struct dhcpv4_serv *dhcpv4, struct dhcpv4_packet if (!ses) goto out; - ses->weight = weight = serv->opt_weight >= 0 ? serv->sess_cnt * serv->opt_weight : (stat_active + 1) * conf_weight; + ses->weight = weight = serv->opt_weight >= 0 ? serv->sess_cnt * serv->opt_weight : (ipoe_stat_active() + 1) * conf_weight; } else { if (ses->terminate) { triton_context_call(ses->ctrl.ctx, (triton_event_func)ipoe_session_terminated, ses); @@ -2003,6 +2035,7 @@ static void ipoe_ses_recv_dhcpv4_relay(struct dhcpv4_packet *pack) if (!ses->dhcpv4_request) { ses->dhcpv4_relay_reply = NULL; + dhcpv4_packet_free(pack); return; } @@ -2110,10 +2143,10 @@ static struct ipoe_session *ipoe_session_create_up(struct ipoe_serv *serv, struc if (ap_shutdown) return NULL; - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) return NULL; - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) return NULL; if (connlimit_loaded && connlimit_check(serv->opt_shared ? cl_key_from_ipv4(saddr) : serv->ifindex)) @@ -2330,7 +2363,7 @@ void ipoe_serv_recv_arp(struct ipoe_serv *serv, struct _arphdr *arph) list_del(&d->entry); mempool_free(d); - __sync_sub_and_fetch(&stat_delayed_offer, 1); + ipoe_stat_dec(&ipoe_stat.delayed_offer); break; } @@ -2627,14 +2660,14 @@ static void ipoe_serv_release(struct ipoe_serv *serv) list_del(&d->entry); dhcpv4_packet_free(d->pack); mempool_free(d); - __sync_sub_and_fetch(&stat_delayed_offer, 1); + ipoe_stat_dec(&ipoe_stat.delayed_offer); } while (!list_empty(&serv->arp_list)) { struct arp_item *d = list_entry(serv->arp_list.next, typeof(*d), entry); list_del(&d->entry); mempool_free(d); - __sync_sub_and_fetch(&stat_delayed_offer, 1); + ipoe_stat_dec(&ipoe_stat.delayed_offer); } while (!list_empty(&serv->req_list)) { @@ -2707,10 +2740,14 @@ static void l4_redirect_ctx_close(struct triton_context_t *ctx) static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) { + struct ipoe_stat_t stat; + + ipoe_stat_get(&stat); + cli_send(client, "ipoe:\r\n"); - cli_sendv(client," starting: %u\r\n", stat_starting); - cli_sendv(client," active: %u\r\n", stat_active); - cli_sendv(client," delayed: %u\r\n", stat_delayed_offer); + cli_sendv(client," starting: %u\r\n", stat.starting); + cli_sendv(client," active: %u\r\n", stat.active); + cli_sendv(client," delayed: %u\r\n", stat.delayed_offer); return CLI_CMD_OK; } @@ -2728,12 +2765,6 @@ static void print_session_type(struct ap_session *s, char *buf) *buf = 0; } -void __export ipoe_get_stat(unsigned int **starting, unsigned int **active) -{ - *starting = &stat_starting; - *active = &stat_active; -} - static void __terminate(struct ap_session *ses) { ap_session_terminate(ses, TERM_NAS_REQUEST, 1); @@ -2771,9 +2802,10 @@ struct ipoe_serv *ipoe_find_serv(const char *ifname) static int get_offer_delay() { struct delay *r, *prev = NULL; + unsigned int active = ipoe_stat_active(); list_for_each_entry(r, &conf_offer_delay, entry) { - if (!prev || stat_active >= r->conn_cnt) { + if (!prev || active >= r->conn_cnt) { prev = r; continue; } @@ -2804,10 +2836,10 @@ void ipoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) struct ifreq ifr; char *ptr; int len, r, svid; - pcre *re = NULL; - const char *pcre_err; + pcre2_code *re = NULL; + int pcre_err; char *pattern; - int pcre_offset; + PCRE2_SIZE pcre_offset; char ifname[IFNAMSIZ]; if (!sect) @@ -2905,15 +2937,17 @@ void ipoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) memcpy(pattern, opt->val + 3, ptr - (opt->val + 3)); pattern[ptr - (opt->val + 3)] = 0; - re = pcre_compile2(pattern, 0, NULL, &pcre_err, &pcre_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, 0, &pcre_err, &pcre_offset, NULL); _free(pattern); if (!re) continue; - r = pcre_exec(re, NULL, ifname, len, 0, 0, NULL, 0); - pcre_free(re); + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + r = pcre2_match(re, (PCRE2_SPTR)ifname, len, 0, 0, match_data, NULL); + pcre2_match_data_free(match_data); + pcre2_code_free(re); if (r < 0) continue; @@ -3109,12 +3143,12 @@ static void add_interface(const char *ifname, int ifindex, const char *opt, int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (connect(sock, &addr, sizeof(addr))) { + if (connect(sock, (struct sockaddr*)&addr, sizeof(addr))) { log_error("dhcpv4: relay: %s: connect: %s\n", opt_relay, strerror(errno)); goto out_err; } - getsockname(sock, &addr, &len); + getsockname(sock, (struct sockaddr*)&addr, &len); opt_giaddr = addr.sin_addr.s_addr; close(sock); @@ -3358,8 +3392,12 @@ static void load_interface(const char *opt) static int __load_interface_re(int index, int flags, const char *name, int iflink, int vid, struct iplink_arg *arg) { - if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0) + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + if (pcre2_match(arg->re, (PCRE2_SPTR)name, strlen(name), 0, 0, match_data, NULL) < 0) { + pcre2_match_data_free(match_data); return 0; + } + pcre2_match_data_free(match_data); add_interface(name, index, arg->opt, iflink, vid, 0); @@ -3368,11 +3406,11 @@ static int __load_interface_re(int index, int flags, const char *name, int iflin static void load_interface_re(const char *opt) { - pcre *re = NULL; - const char *pcre_err; + pcre2_code *re = NULL; + int pcre_err; char *pattern; const char *ptr; - int pcre_offset; + PCRE2_SIZE pcre_offset; struct iplink_arg arg; struct ipoe_serv *serv; @@ -3382,10 +3420,12 @@ static void load_interface_re(const char *opt) memcpy(pattern, opt + 3, ptr - (opt + 3)); pattern[ptr - (opt + 3)] = 0; - re = pcre_compile2(pattern, 0, NULL, &pcre_err, &pcre_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, 0, &pcre_err, &pcre_offset, NULL); if (!re) { - log_error("ipoe: '%s': %s at %i\r\n", pattern, pcre_err, pcre_offset); + PCRE2_UCHAR err_msg[64]; + pcre2_get_error_message(pcre_err, err_msg, sizeof(err_msg)); + log_error("ipoe: '%s': %s at %i\r\n", pattern, err_msg, (int)pcre_offset); return; } @@ -3398,11 +3438,13 @@ static void load_interface_re(const char *opt) if (serv->active) continue; - if (pcre_exec(re, NULL, serv->ifname, strlen(serv->ifname), 0, 0, NULL, 0) >= 0) + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + if (pcre2_match(re, (PCRE2_SPTR)serv->ifname, strlen(serv->ifname), 0, 0, match_data, NULL) >= 0) add_interface(serv->ifname, serv->ifindex, opt, 0, 0, 0); + pcre2_match_data_free(match_data); } - pcre_free(re); + pcre2_code_free(re); _free(pattern); } @@ -3474,7 +3516,7 @@ static void load_gw_addr(struct conf_sect_t *sect) continue; } - a->mask1 = ((1 << a->mask) - 1) << (32 - a->mask); + a->mask1 = (int)(((1u << a->mask) - 1u) << (32 - a->mask)); list_add_tail(&a->entry, &conf_gw_addr); } } @@ -3538,19 +3580,6 @@ static void load_radius_attrs(void) } #endif -static void strip(char *str) -{ - char *ptr = str; - char *endptr = strchr(str, 0); - while (1) { - ptr = strchr(ptr, ' '); - if (ptr) - memmove(ptr, ptr + 1, endptr - ptr - 1); - else - break; - } -} - int parse_offer_delay(const char *str) { char *str1; @@ -3567,7 +3596,7 @@ int parse_offer_delay(const char *str) return 0; str1 = _strdup(str); - strip(str1); + u_strstrip(str1, ' '); ptr1 = str1; @@ -3583,17 +3612,23 @@ int parse_offer_delay(const char *str) memset(r, 0, sizeof(*r)); r->delay = strtol(ptr1, &endptr, 10); - if (*endptr) + if (*endptr) { + _free(r); goto out_err; + } if (list_empty(&conf_offer_delay)) r->conn_cnt = 0; else { - if (!ptr3) + if (!ptr3) { + _free(r); goto out_err; + } r->conn_cnt = strtol(ptr3 + 1, &endptr, 10); - if (*endptr) + if (*endptr) { + _free(r); goto out_err; + } } list_add_tail(&r->entry, &conf_offer_delay); @@ -3608,6 +3643,11 @@ int parse_offer_delay(const char *str) return 0; out_err: + while (!list_empty(&conf_offer_delay)) { + r = list_entry(conf_offer_delay.next, typeof(*r), entry); + list_del(&r->entry); + _free(r); + } _free(str1); log_error("ipoe: failed to parse offer-delay\n"); return -1; @@ -3670,8 +3710,12 @@ static int __load_vlan_mon_re(int index, int flags, const char *name, int iflink long mask1[4096/8/sizeof(long)]; struct ipoe_serv *serv; - if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0) + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + if (pcre2_match(arg->re, (PCRE2_SPTR)name, strlen(name), 0, 0, match_data, NULL) < 0) { + pcre2_match_data_free(match_data); return 0; + } + pcre2_match_data_free(match_data); if (!(flags & IFF_UP)) { memset(&ifr, 0, sizeof(ifr)); @@ -3701,11 +3745,11 @@ static int __load_vlan_mon_re(int index, int flags, const char *name, int iflink static void load_vlan_mon_re(const char *opt, long *mask, int len) { - pcre *re = NULL; - const char *pcre_err; + pcre2_code *re = NULL; + int pcre_err; char *pattern; const char *ptr; - int pcre_offset; + PCRE2_SIZE pcre_offset; struct iplink_arg arg; for (ptr = opt; *ptr && *ptr != ','; ptr++); @@ -3714,10 +3758,12 @@ static void load_vlan_mon_re(const char *opt, long *mask, int len) memcpy(pattern, opt + 3, ptr - (opt + 3)); pattern[ptr - (opt + 3)] = 0; - re = pcre_compile2(pattern, 0, NULL, &pcre_err, &pcre_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, 0, &pcre_err, &pcre_offset, NULL); if (!re) { - log_error("ipoe: '%s': %s at %i\r\n", pattern, pcre_err, pcre_offset); + PCRE2_UCHAR err_msg[64]; + pcre2_get_error_message(pcre_err, err_msg, sizeof(err_msg)); + log_error("ipoe: '%s': %s at %i\r\n", pattern, err_msg, (int)pcre_offset); return; } @@ -3727,7 +3773,7 @@ static void load_vlan_mon_re(const char *opt, long *mask, int len) iplink_list((iplink_list_func)__load_vlan_mon_re, &arg); - pcre_free(re); + pcre2_code_free(re); _free(pattern); } diff --git a/accel-pppd/ctrl/ipoe/ipoe.h b/accel-pppd/ctrl/ipoe/ipoe.h index 116602be..37c26a63 100644 --- a/accel-pppd/ctrl/ipoe/ipoe.h +++ b/accel-pppd/ctrl/ipoe/ipoe.h @@ -3,7 +3,7 @@ #include <stdint.h> #include <pthread.h> -#include <linux/if.h> +#include <net/if.h> #include "triton.h" #include "ap_session.h" @@ -130,6 +130,17 @@ struct ipoe_session_info { uint32_t peer_addr; }; +struct ipoe_stat_t +{ + unsigned int starting; + unsigned int active; + unsigned int delayed_offer; +}; + +void ipoe_stat_get(struct ipoe_stat_t *stat); +unsigned int ipoe_stat_starting(void); +unsigned int ipoe_stat_active(void); + int ipoe_ipv6_nd_start(struct ipoe_serv *serv); #ifdef USE_LUA diff --git a/accel-pppd/ctrl/ipoe/ipoe_netlink.c b/accel-pppd/ctrl/ipoe/ipoe_netlink.c index e7080e92..7057c91e 100644 --- a/accel-pppd/ctrl/ipoe/ipoe_netlink.c +++ b/accel-pppd/ctrl/ipoe/ipoe_netlink.c @@ -10,7 +10,7 @@ #include <net/ethernet.h> #include <netinet/ip.h> #include <arpa/inet.h> -#include <linux/if.h> +#include <net/if.h> #include <linux/genetlink.h> #include "triton.h" diff --git a/accel-pppd/ctrl/l2tp/CMakeLists.txt b/accel-pppd/ctrl/l2tp/CMakeLists.txt index 66dd3fc6..80cf453b 100644 --- a/accel-pppd/ctrl/l2tp/CMakeLists.txt +++ b/accel-pppd/ctrl/l2tp/CMakeLists.txt @@ -8,10 +8,10 @@ ADD_LIBRARY(l2tp SHARED packet.c # netlink.c ) +TARGET_LINK_LIBRARIES(l2tp ${crypto_lib}) #TARGET_LINK_LIBRARIES(l2tp nl nl-genl) INSTALL(TARGETS l2tp LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp) FILE(GLOB dict "${CMAKE_CURRENT_SOURCE_DIR}/dict/*") INSTALL(FILES ${dict} DESTINATION share/accel-ppp/l2tp) - diff --git a/accel-pppd/ctrl/l2tp/l2tp.c b/accel-pppd/ctrl/l2tp/l2tp.c index bb1d1699..cf0c502c 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.c +++ b/accel-pppd/ctrl/l2tp/l2tp.c @@ -16,6 +16,8 @@ #include <linux/if_ether.h> #include <linux/if_pppox.h> +#include <openssl/md5.h> + #include "triton.h" #include "mempool.h" #include "log.h" @@ -24,7 +26,6 @@ #include "utils.h" #include "iprange.h" #include "cli.h" -#include "crypto.h" #include "connlimit.h" @@ -99,17 +100,22 @@ static const char *conf_ipv6_pool; static const char *conf_dpv6_pool; static const char *conf_ifname; -static unsigned int stat_conn_starting; -static unsigned int stat_conn_active; -static unsigned int stat_conn_finishing; +struct l2tp_stat_t +{ + unsigned int conn_starting; + unsigned int conn_active; + unsigned int conn_finishing; -static unsigned int stat_sess_starting; -static unsigned int stat_sess_active; -static unsigned int stat_sess_finishing; + unsigned int sess_starting; + unsigned int sess_active; + unsigned int sess_finishing; -static unsigned int stat_active; -static unsigned int stat_starting; -static unsigned int stat_finishing; + unsigned int data_starting; + unsigned int data_active; + unsigned int data_finishing; +}; + +static struct l2tp_stat_t l2tp_stat; struct l2tp_serv_t { @@ -123,6 +129,11 @@ struct l2tp_sess_t struct l2tp_conn_t *paren_conn; uint16_t sid; uint16_t peer_sid; +/* We will keep l2tp attributes Calling-Number/Called-Number and their length while the session exists */ + char *calling_num; + int calling_num_len; + char *called_num; + int called_num_len; unsigned int ref_count; int state1; @@ -199,6 +210,45 @@ static void l2tp_session_free(struct l2tp_sess_t *sess); static void l2tp_tunnel_free(struct l2tp_conn_t *conn); static void apses_stop(void *data); +static void l2tp_stat_inc(unsigned int *stat) +{ + __atomic_add_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void l2tp_stat_dec(unsigned int *stat) +{ + __atomic_sub_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void l2tp_stat_move(unsigned int *from, unsigned int *to) +{ + l2tp_stat_dec(from); + l2tp_stat_inc(to); +} + +static void l2tp_stat_get(struct l2tp_stat_t *stat) +{ + stat->conn_starting = __atomic_load_n(&l2tp_stat.conn_starting, __ATOMIC_RELAXED); + stat->conn_active = __atomic_load_n(&l2tp_stat.conn_active, __ATOMIC_RELAXED); + stat->conn_finishing = __atomic_load_n(&l2tp_stat.conn_finishing, __ATOMIC_RELAXED); + stat->sess_starting = __atomic_load_n(&l2tp_stat.sess_starting, __ATOMIC_RELAXED); + stat->sess_active = __atomic_load_n(&l2tp_stat.sess_active, __ATOMIC_RELAXED); + stat->sess_finishing = __atomic_load_n(&l2tp_stat.sess_finishing, __ATOMIC_RELAXED); + stat->data_starting = __atomic_load_n(&l2tp_stat.data_starting, __ATOMIC_RELAXED); + stat->data_active = __atomic_load_n(&l2tp_stat.data_active, __ATOMIC_RELAXED); + stat->data_finishing = __atomic_load_n(&l2tp_stat.data_finishing, __ATOMIC_RELAXED); +} + +unsigned int __export l2tp_stat_starting(void) +{ + return __atomic_load_n(&l2tp_stat.data_starting, __ATOMIC_RELAXED); +} + +unsigned int __export l2tp_stat_active(void) +{ + return __atomic_load_n(&l2tp_stat.data_active, __ATOMIC_RELAXED); +} + #define log_tunnel(log_func, conn, fmt, ...) \ do { \ @@ -848,16 +898,17 @@ out_err: return -1; } +static void l2tp_session_free_ptr(void *ptr) +{ + l2tp_session_free((struct l2tp_sess_t *) ptr); +} + static void l2tp_tunnel_free_sessions(struct l2tp_conn_t *conn) { void *sessions = conn->sessions; conn->sessions = NULL; -#ifdef HAVE_FREE_FN_T - tdestroy(sessions, (__free_fn_t)l2tp_session_free); -#else - tdestroy(sessions, (void(*)(void *))l2tp_session_free); -#endif + tdestroy(sessions, l2tp_session_free_ptr); /* Let l2tp_session_free() handle the session counter and * the reference held by the tunnel. */ @@ -870,12 +921,10 @@ static int l2tp_tunnel_disconnect(struct l2tp_conn_t *conn, case STATE_INIT: case STATE_WAIT_SCCRP: case STATE_WAIT_SCCCN: - __sync_sub_and_fetch(&stat_conn_starting, 1); - __sync_add_and_fetch(&stat_conn_finishing, 1); + l2tp_stat_move(&l2tp_stat.conn_starting, &l2tp_stat.conn_finishing); break; case STATE_ESTB: - __sync_sub_and_fetch(&stat_conn_active, 1); - __sync_add_and_fetch(&stat_conn_finishing, 1); + l2tp_stat_move(&l2tp_stat.conn_active, &l2tp_stat.conn_finishing); break; case STATE_FIN: case STATE_FIN_WAIT: @@ -955,7 +1004,7 @@ static void __tunnel_destroy(struct l2tp_conn_t *conn) mempool_free(conn); - __sync_sub_and_fetch(&stat_conn_finishing, 1); + l2tp_stat_dec(&l2tp_stat.conn_finishing); } static void tunnel_put(struct l2tp_conn_t *conn) @@ -983,12 +1032,16 @@ static void __session_destroy(struct l2tp_sess_t *sess) _free(sess->ctrl.calling_station_id); if (sess->ctrl.called_station_id) _free(sess->ctrl.called_station_id); + if (sess->calling_num) + _free(sess->calling_num); + if (sess->called_num) + _free(sess->called_num); log_session(log_info2, sess, "session destroyed\n"); mempool_free(sess); - __sync_sub_and_fetch(&stat_sess_finishing, 1); + l2tp_stat_dec(&l2tp_stat.sess_finishing); /* Now that the session is fully destroyed, * drop the reference to the tunnel. @@ -1021,15 +1074,13 @@ static void l2tp_session_free(struct l2tp_sess_t *sess) case STATE_WAIT_OCCN: log_session(log_info2, sess, "deleting session\n"); - __sync_sub_and_fetch(&stat_sess_starting, 1); - __sync_add_and_fetch(&stat_sess_finishing, 1); + l2tp_stat_move(&l2tp_stat.sess_starting, &l2tp_stat.sess_finishing); break; case STATE_ESTB: log_session(log_info2, sess, "deleting session\n"); triton_event_fire(EV_CTRL_FINISHED, &sess->ppp.ses); - __sync_sub_and_fetch(&stat_sess_active, 1); - __sync_add_and_fetch(&stat_sess_finishing, 1); + l2tp_stat_move(&l2tp_stat.sess_active, &l2tp_stat.sess_finishing); pthread_mutex_lock(&sess->apses_lock); if (sess->apses_ctx.tpd) @@ -1124,12 +1175,10 @@ static void l2tp_tunnel_free(struct l2tp_conn_t *conn) case STATE_INIT: case STATE_WAIT_SCCRP: case STATE_WAIT_SCCCN: - __sync_sub_and_fetch(&stat_conn_starting, 1); - __sync_add_and_fetch(&stat_conn_finishing, 1); + l2tp_stat_move(&l2tp_stat.conn_starting, &l2tp_stat.conn_finishing); break; case STATE_ESTB: - __sync_sub_and_fetch(&stat_conn_active, 1); - __sync_add_and_fetch(&stat_conn_finishing, 1); + l2tp_stat_move(&l2tp_stat.conn_active, &l2tp_stat.conn_finishing); break; case STATE_FIN: case STATE_FIN_WAIT: @@ -1252,7 +1301,7 @@ static void __apses_destroy(void *data) log_ppp_info2("session destroyed\n"); - __sync_sub_and_fetch(&stat_finishing, 1); + l2tp_stat_dec(&l2tp_stat.data_finishing); /* Drop reference to the L2TP session */ session_put(sess); @@ -1267,12 +1316,10 @@ static void apses_finished(struct ap_session *apses) switch (sess->apses_state) { case APSTATE_STARTING: - __sync_sub_and_fetch(&stat_starting, 1); - __sync_add_and_fetch(&stat_finishing, 1); + l2tp_stat_move(&l2tp_stat.data_starting, &l2tp_stat.data_finishing); break; case APSTATE_STARTED: - __sync_sub_and_fetch(&stat_active, 1); - __sync_add_and_fetch(&stat_finishing, 1); + l2tp_stat_move(&l2tp_stat.data_active, &l2tp_stat.data_finishing); break; case APSTATE_FINISHING: break; @@ -1313,12 +1360,10 @@ static void apses_stop(void *data) switch (sess->apses_state) { case APSTATE_INIT: case APSTATE_STARTING: - __sync_sub_and_fetch(&stat_starting, 1); - __sync_add_and_fetch(&stat_finishing, 1); + l2tp_stat_move(&l2tp_stat.data_starting, &l2tp_stat.data_finishing); break; case APSTATE_STARTED: - __sync_sub_and_fetch(&stat_active, 1); - __sync_add_and_fetch(&stat_finishing, 1); + l2tp_stat_move(&l2tp_stat.data_active, &l2tp_stat.data_finishing); break; case APSTATE_FINISHING: break; @@ -1377,8 +1422,7 @@ static void apses_started(struct ap_session *apses) return; } - __sync_sub_and_fetch(&stat_starting, 1); - __sync_add_and_fetch(&stat_active, 1); + l2tp_stat_move(&l2tp_stat.data_starting, &l2tp_stat.data_active); sess->apses_state = APSTATE_STARTED; log_ppp_info1("session started over l2tp session %hu-%hu, %hu-%hu\n", @@ -1507,7 +1551,7 @@ static struct l2tp_sess_t *l2tp_tunnel_alloc_session(struct l2tp_conn_t *conn) tunnel_hold(conn); session_hold(sess); - __sync_add_and_fetch(&stat_sess_starting, 1); + l2tp_stat_inc(&l2tp_stat.sess_starting); return sess; } @@ -1613,7 +1657,7 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer, strerror(errno)); goto err_conn_fd; } - if (bind(conn->hnd.fd, host, sizeof(*host))) { + if (bind(conn->hnd.fd, (struct sockaddr*)host, sizeof(*host))) { log_error("l2tp: impossible to allocate new tunnel:" " bind() failed: %s\n", strerror(errno)); goto err_conn_fd; @@ -1646,7 +1690,7 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer, goto err_conn_fd; } - if (getsockname(conn->hnd.fd, &conn->host_addr, &hostaddrlen) < 0) { + if (getsockname(conn->hnd.fd, (struct sockaddr*)&conn->host_addr, &hostaddrlen) < 0) { log_error("l2tp: impossible to allocate new tunnel:" " getsockname() failed: %s\n", strerror(errno)); goto err_conn_fd; @@ -1726,7 +1770,7 @@ static struct l2tp_conn_t *l2tp_tunnel_alloc(const struct sockaddr_in *peer, conn->peer_rcv_wnd_sz = DEFAULT_PEER_RECV_WINDOW_SIZE; tunnel_hold(conn); - __sync_add_and_fetch(&stat_conn_starting, 1); + l2tp_stat_inc(&l2tp_stat.conn_starting); return conn; @@ -1747,7 +1791,7 @@ static inline int l2tp_tunnel_update_peerport(struct l2tp_conn_t *conn, int res; conn->peer_addr.sin_port = port_nbo; - res = connect(conn->hnd.fd, &conn->peer_addr, sizeof(conn->peer_addr)); + res = connect(conn->hnd.fd, (struct sockaddr*)&conn->peer_addr, sizeof(conn->peer_addr)); if (res < 0) { log_tunnel(log_error, conn, "impossible to update peer port from %hu to %hu:" @@ -1775,25 +1819,52 @@ static int l2tp_session_start_data_channel(struct l2tp_sess_t *sess) sess->ctrl.max_mtu = conf_ppp_max_mtu; sess->ctrl.mppe = conf_mppe; - sess->ctrl.calling_station_id = _malloc(17); - if (sess->ctrl.calling_station_id == NULL) { - log_session(log_error, sess, - "impossible to start data channel:" - " allocation of calling station ID failed\n"); - goto err; + /* If l2tp calling number avp exists, we use it, otherwise we use lac ip */ + if (sess->calling_num != NULL) { + sess->ctrl.calling_station_id = _malloc(sess->calling_num_len+1); + if (sess->ctrl.calling_station_id == NULL) { + log_session(log_error, sess, + "impossible to start data channel:" + " allocation of calling station ID failed\n"); + goto err; + }else { + strcpy(sess->ctrl.calling_station_id, sess->calling_num); + } + } else { + sess->ctrl.calling_station_id = _malloc(17); + if (sess->ctrl.calling_station_id == NULL) { + log_session(log_error, sess, + "impossible to start data channel:" + " allocation of calling station ID failed\n"); + goto err; + } else { + u_inet_ntoa(sess->paren_conn->peer_addr.sin_addr.s_addr, + sess->ctrl.calling_station_id); + } } - u_inet_ntoa(sess->paren_conn->peer_addr.sin_addr.s_addr, - sess->ctrl.calling_station_id); - - sess->ctrl.called_station_id = _malloc(17); - if (sess->ctrl.called_station_id == NULL) { - log_session(log_error, sess, - "impossible to start data channel:" - " allocation of called station ID failed\n"); - goto err; + /* If l2tp called number avp exists, we use it, otherwise we use my ip */ + if (sess->called_num != NULL) { + sess->ctrl.called_station_id = _malloc(sess->called_num_len+1); + if (sess->ctrl.called_station_id == NULL) { + log_session(log_error, sess, + "impossible to start data channel:" + " allocation of called station ID failed\n"); + goto err; + } else { + strcpy(sess->ctrl.called_station_id, sess->called_num); + } + } else { + sess->ctrl.called_station_id = _malloc(17); + if (sess->ctrl.called_station_id == NULL) { + log_session(log_error, sess, + "impossible to start data channel:" + " allocation of called station ID failed\n"); + goto err; + } else { + u_inet_ntoa(sess->paren_conn->host_addr.sin_addr.s_addr, + sess->ctrl.called_station_id); + } } - u_inet_ntoa(sess->paren_conn->host_addr.sin_addr.s_addr, - sess->ctrl.called_station_id); if (conf_ip_pool) { sess->ppp.ses.ipv4_pool_name = _strdup(conf_ip_pool); @@ -1844,7 +1915,7 @@ static int l2tp_session_start_data_channel(struct l2tp_sess_t *sess) goto err_put_ctx; } - __sync_add_and_fetch(&stat_starting, 1); + l2tp_stat_inc(&l2tp_stat.data_starting); return 0; @@ -1974,8 +2045,7 @@ static int l2tp_session_connect(struct l2tp_sess_t *sess) } triton_event_fire(EV_CTRL_STARTED, &sess->ppp.ses); - __sync_sub_and_fetch(&stat_sess_starting, 1); - __sync_add_and_fetch(&stat_sess_active, 1); + l2tp_stat_move(&l2tp_stat.sess_starting, &l2tp_stat.sess_active); sess->state1 = STATE_ESTB; if (l2tp_session_start_data_channel(sess) < 0) { @@ -2053,8 +2123,7 @@ static int l2tp_tunnel_connect(struct l2tp_conn_t *conn) close(tunnel_fd); - __sync_sub_and_fetch(&stat_conn_starting, 1); - __sync_add_and_fetch(&stat_conn_active, 1); + l2tp_stat_move(&l2tp_stat.conn_starting, &l2tp_stat.conn_active); conn->state = STATE_ESTB; return 0; @@ -2684,12 +2753,10 @@ static void l2tp_tunnel_finwait(struct l2tp_conn_t *conn) switch (conn->state) { case STATE_WAIT_SCCRP: case STATE_WAIT_SCCCN: - __sync_sub_and_fetch(&stat_conn_starting, 1); - __sync_add_and_fetch(&stat_conn_finishing, 1); + l2tp_stat_move(&l2tp_stat.conn_starting, &l2tp_stat.conn_finishing); break; case STATE_ESTB: - __sync_sub_and_fetch(&stat_conn_active, 1); - __sync_add_and_fetch(&stat_conn_finishing, 1); + l2tp_stat_move(&l2tp_stat.conn_active, &l2tp_stat.conn_finishing); break; case STATE_FIN: break; @@ -2769,10 +2836,10 @@ static int l2tp_recv_SCCRQ(const struct l2tp_serv_t *serv, return 0; } - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) return 0; - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) return 0; if (triton_module_loaded("connlimit") @@ -3299,6 +3366,10 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, uint16_t sid = 0; uint16_t res = 0; uint16_t err = 0; + uint8_t calling[L2TP_AVP_LEN_MASK] = {0}; + uint8_t called[L2TP_AVP_LEN_MASK] = {0}; + int n = 0; + int m = 0; if (conn->state != STATE_ESTB && conn->lns_mode) { log_tunnel(log_warn, conn, "discarding unexpected ICRQ\n"); @@ -3311,10 +3382,10 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, return 0; } - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) return 0; - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) return 0; if (triton_module_loaded("connlimit") @@ -3336,7 +3407,17 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, case Call_Serial_Number: case Bearer_Type: case Calling_Number: + /* Save Calling-Number L2TP attribute locally */ + if (attr->attr->id == Calling_Number) { + n = attr->length; + memcpy(calling,attr->val.octets,n); + } case Called_Number: + /* Save Called-Number L2TP attribute locally */ + if (attr->attr->id == Called_Number) { + m = attr->length; + memcpy(called,attr->val.octets,m); + } case Sub_Address: case Physical_Channel_ID: break; @@ -3375,6 +3456,30 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, sess->peer_sid = peer_sid; sid = sess->sid; + /* Allocate memory for Calling-Number if exists, and put it to l2tp_sess_t structure */ + if (n > 0) { + sess->calling_num = _malloc(n+1); + if (sess->calling_num == NULL) { + log_tunnel(log_warn, conn, "can't allocate memory for Calling Number attribute. Will use LAC IP instead\n"); + }else{ + memcpy(sess->calling_num, calling, n); + sess->calling_num[n] = '\0'; + sess->calling_num_len = n; + } + } + + /* Allocate memory for Called-Number if exists, and put it to l2tp_sess_t structure */ + if (m > 1) { + sess->called_num = _malloc(m+1); + if (sess->called_num == NULL) { + log_tunnel(log_warn, conn, "can't allocate memory for Called Number attribute. Will use my IP instead\n"); + } else { + memcpy(sess->called_num, called, m); + sess->called_num[m] = '\0'; + sess->called_num_len = m; + } + } + if (unknown_attr) { log_tunnel(log_error, conn, "impossible to handle ICRQ:" " unknown mandatory attribute type %i," @@ -3394,8 +3499,8 @@ static int l2tp_recv_ICRQ(struct l2tp_conn_t *conn, goto out_reject; } - log_tunnel(log_info1, conn, "new session %hu-%hu created following" - " reception of ICRQ\n", sid, peer_sid); + log_tunnel(log_info1, conn, "new session %hu-%hu with calling num %s len %d, called num %s len %d created following" + " reception of ICRQ\n", sid, peer_sid, sess->calling_num, sess->calling_num_len, sess->called_num, sess->called_num_len); return 0; @@ -3617,10 +3722,10 @@ static int l2tp_recv_OCRQ(struct l2tp_conn_t *conn, return 0; } - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) return 0; - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) return 0; if (triton_module_loaded("connlimit") @@ -4637,21 +4742,25 @@ err_fd: static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) { + struct l2tp_stat_t stat; + + l2tp_stat_get(&stat); + cli_send(client, "l2tp:\r\n"); cli_send(client, " tunnels:\r\n"); - cli_sendv(client, " starting: %u\r\n", stat_conn_starting); - cli_sendv(client, " active: %u\r\n", stat_conn_active); - cli_sendv(client, " finishing: %u\r\n", stat_conn_finishing); + cli_sendv(client, " starting: %u\r\n", stat.conn_starting); + cli_sendv(client, " active: %u\r\n", stat.conn_active); + cli_sendv(client, " finishing: %u\r\n", stat.conn_finishing); cli_send(client, " sessions (control channels):\r\n"); - cli_sendv(client, " starting: %u\r\n", stat_sess_starting); - cli_sendv(client, " active: %u\r\n", stat_sess_active); - cli_sendv(client, " finishing: %u\r\n", stat_sess_finishing); + cli_sendv(client, " starting: %u\r\n", stat.sess_starting); + cli_sendv(client, " active: %u\r\n", stat.sess_active); + cli_sendv(client, " finishing: %u\r\n", stat.sess_finishing); cli_send(client, " sessions (data channels):\r\n"); - cli_sendv(client, " starting: %u\r\n", stat_starting); - cli_sendv(client, " active: %u\r\n", stat_active); - cli_sendv(client, " finishing: %u\r\n", stat_finishing); + cli_sendv(client, " starting: %u\r\n", stat.data_starting); + cli_sendv(client, " active: %u\r\n", stat.data_active); + cli_sendv(client, " finishing: %u\r\n", stat.data_finishing); return CLI_CMD_OK; } @@ -4857,12 +4966,6 @@ static void l2tp_create_session_help(char * const *fields, int fields_cnt, " - place new call in tunnel <tid>\r\n"); } -void __export l2tp_get_stat(unsigned int **starting, unsigned int **active) -{ - *starting = &stat_starting; - *active = &stat_active; -} - static void load_config(void) { const char *opt; diff --git a/accel-pppd/ctrl/l2tp/l2tp.h b/accel-pppd/ctrl/l2tp/l2tp.h index 76de867f..2f113a25 100644 --- a/accel-pppd/ctrl/l2tp/l2tp.h +++ b/accel-pppd/ctrl/l2tp/l2tp.h @@ -77,6 +77,9 @@ struct l2tp_packet_t extern int conf_verbose; extern int conf_avp_permissive; +unsigned int l2tp_stat_starting(void); +unsigned int l2tp_stat_active(void); + static inline int l2tp_packet_is_ZLB(const struct l2tp_packet_t *pack) { return list_empty(&pack->attrs); diff --git a/accel-pppd/ctrl/l2tp/packet.c b/accel-pppd/ctrl/l2tp/packet.c index 97e205f3..1e1488b5 100644 --- a/accel-pppd/ctrl/l2tp/packet.c +++ b/accel-pppd/ctrl/l2tp/packet.c @@ -8,7 +8,8 @@ #include <fcntl.h> #include <arpa/inet.h> -#include "crypto.h" +#include <openssl/md5.h> + #include "triton.h" #include "log.h" #include "mempool.h" @@ -280,7 +281,7 @@ int l2tp_recv(int fd, struct l2tp_packet_t **p, struct in_pktinfo *pkt_info, ptr = (uint8_t *)(hdr + 1); addr_len = sizeof(addr); - n = recvfrom(fd, buf, L2TP_MAX_PACKET_SIZE, 0, &addr, &addr_len); + n = recvfrom(fd, buf, L2TP_MAX_PACKET_SIZE, 0, (struct sockaddr*)&addr, &addr_len); if (n < 0) { mempool_free(buf); if (errno == EAGAIN) { @@ -552,7 +553,7 @@ int l2tp_packet_send(int sock, struct l2tp_packet_t *pack) memcpy(buf, &pack->hdr, sizeof(pack->hdr)); hdr->flags = htons(pack->hdr.flags); - n = sendto(sock, buf, len, 0, &pack->addr, sizeof(pack->addr)); + n = sendto(sock, buf, len, 0, (struct sockaddr*)&pack->addr, sizeof(pack->addr)); mempool_free(buf); if (n < 0) { diff --git a/accel-pppd/ctrl/pppoe/CMakeLists.txt b/accel-pppd/ctrl/pppoe/CMakeLists.txt index fd4f9a36..92733b74 100644 --- a/accel-pppd/ctrl/pppoe/CMakeLists.txt +++ b/accel-pppd/ctrl/pppoe/CMakeLists.txt @@ -13,7 +13,12 @@ SET(sources ${sources} tr101.c) ENDIF(RADIUS) ADD_LIBRARY(pppoe SHARED ${sources}) -TARGET_LINK_LIBRARIES(pppoe vlan-mon connlimit) +# if MUSL is set then we need to link with the connlimit library +IF (MUSL) + TARGET_LINK_LIBRARIES(pppoe vlan-mon connlimit ${crypto_lib}) +ELSE (MUSL) + TARGET_LINK_LIBRARIES(pppoe vlan-mon ${crypto_lib}) +ENDIF (MUSL) set_property(TARGET pppoe PROPERTY CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set_property(TARGET pppoe PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/accel-ppp) diff --git a/accel-pppd/ctrl/pppoe/cli.c b/accel-pppd/ctrl/pppoe/cli.c index d8399543..453c0cf3 100644 --- a/accel-pppd/ctrl/pppoe/cli.c +++ b/accel-pppd/ctrl/pppoe/cli.c @@ -88,16 +88,20 @@ help: static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) { + struct pppoe_stat_t stat; + + pppoe_stat_get(&stat); + cli_send(client, "pppoe:\r\n"); - cli_sendv(client, " starting: %u\r\n", stat_starting); - cli_sendv(client, " active: %u\r\n", stat_active); - cli_sendv(client, " delayed PADO: %u\r\n", stat_delayed_pado); - cli_sendv(client, " recv PADI: %lu\r\n", stat_PADI_recv); - cli_sendv(client, " drop PADI: %lu\r\n", stat_PADI_drop); - cli_sendv(client, " sent PADO: %lu\r\n", stat_PADO_sent); - cli_sendv(client, " recv PADR(dup): %lu(%lu)\r\n", stat_PADR_recv, stat_PADR_dup_recv); - cli_sendv(client, " sent PADS: %lu\r\n", stat_PADS_sent); - cli_sendv(client, " filtered: %lu\r\n", stat_filtered); + cli_sendv(client, " starting: %u\r\n", stat.starting); + cli_sendv(client, " active: %u\r\n", stat.active); + cli_sendv(client, " delayed PADO: %u\r\n", stat.delayed_PADO); + cli_sendv(client, " recv PADI: %lu\r\n", stat.PADI_recv); + cli_sendv(client, " drop PADI: %lu\r\n", stat.PADI_drop); + cli_sendv(client, " sent PADO: %lu\r\n", stat.PADO_sent); + cli_sendv(client, " recv PADR(dup): %lu(%lu)\r\n", stat.PADR_recv, stat.PADR_dup_recv); + cli_sendv(client, " sent PADS: %lu\r\n", stat.PADS_sent); + cli_sendv(client, " filtered: %lu\r\n", stat.filtered); return CLI_CMD_OK; } diff --git a/accel-pppd/ctrl/pppoe/disc.c b/accel-pppd/ctrl/pppoe/disc.c index 8a82e1d2..f7f5c781 100644 --- a/accel-pppd/ctrl/pppoe/disc.c +++ b/accel-pppd/ctrl/pppoe/disc.c @@ -77,7 +77,7 @@ static struct disc_net *init_net(const struct ap_net *net) fcntl(sock, F_SETFD, FD_CLOEXEC); net->set_nonblocking(sock, 1); - n = _malloc(sizeof(*net) + (HASH_BITS + 1) * sizeof(struct tree)); + n = _malloc(sizeof(*n) + (HASH_BITS + 1) * sizeof(struct tree)); tree = n->tree; for (i = 0; i <= HASH_BITS; i++) { @@ -110,7 +110,7 @@ static void free_net(struct disc_net *net) pthread_mutex_lock(&nets_lock); for (i = 0; i < MAX_NET; i++) { if (nets[i] == net) { - memcpy(nets + i, nets + i + 1, net_cnt - i - 1); + memmove(nets + i, nets + i + 1, (net_cnt - i - 1) * sizeof(nets[0])); net_cnt--; break; } @@ -329,7 +329,7 @@ static int disc_read(struct triton_md_handler_t *h) } if (mac_filter_check(ethhdr->h_source)) { - __sync_add_and_fetch(&stat_filtered, 1); + pppoe_stat_add_filtered(); continue; } @@ -363,6 +363,7 @@ static int disc_read(struct triton_md_handler_t *h) if (hdr->type != 1) { if (conf_verbose) log_warn("pppoe: discarding packet (unsupported type %i)\n", hdr->type); + continue; } if (forward(net, src.sll_ifindex, pack, n)) diff --git a/accel-pppd/ctrl/pppoe/dpado.c b/accel-pppd/ctrl/pppoe/dpado.c index 71faa130..dc570dda 100644 --- a/accel-pppd/ctrl/pppoe/dpado.c +++ b/accel-pppd/ctrl/pppoe/dpado.c @@ -11,6 +11,7 @@ #include "triton.h" #include "log.h" #include "memdebug.h" +#include "utils.h" #include "pppoe.h" @@ -60,27 +61,15 @@ void dpado_check_prev(int conn_cnt) pthread_mutex_unlock(&dpado_range_lock); } -static void strip(char *str) -{ - char *ptr = str; - char *endptr = strchr(str, 0); - while (1) { - ptr = strchr(ptr, ' '); - if (ptr) - memmove(ptr, ptr + 1, endptr - ptr - 1); - else - break; - } -} - int dpado_parse(const char *str) { char *str1 = _strdup(str); char *ptr1, *ptr2, *ptr3, *endptr; + unsigned int active = pppoe_stat_active(); LIST_HEAD(range_list); struct dpado_range_t *r; - strip(str1); + u_strstrip(str1, ' '); ptr1 = str1; @@ -96,17 +85,23 @@ int dpado_parse(const char *str) memset(r, 0, sizeof(*r)); r->pado_delay = strtol(ptr1, &endptr, 10); - if (*endptr) + if (*endptr) { + _free(r); goto out_err; + } if (list_empty(&range_list)) r->conn_cnt = INT_MAX; else { - if (!ptr3) + if (!ptr3) { + _free(r); goto out_err; + } r->conn_cnt = strtol(ptr3 + 1, &endptr, 10); - if (*endptr) + if (*endptr) { + _free(r); goto out_err; + } } list_add_tail(&r->entry, &range_list); @@ -131,7 +126,7 @@ int dpado_parse(const char *str) dpado_range_prev = NULL; list_for_each_entry(r, &dpado_range_list, entry) { - if (!dpado_range_prev || stat_active >= r->conn_cnt) { + if (!dpado_range_prev || active >= r->conn_cnt) { dpado_range_prev = r; if (r->entry.next != &dpado_range_list) dpado_range_next = list_entry(r->entry.next, typeof(*r), entry); @@ -159,6 +154,11 @@ int dpado_parse(const char *str) return 0; out_err: + while (!list_empty(&range_list)) { + r = list_entry(range_list.next, typeof(*r), entry); + list_del(&r->entry); + _free(r); + } _free(str1); log_emerg("pppoe: pado_delay: invalid format\n"); return -1; diff --git a/accel-pppd/ctrl/pppoe/mac_filter.c b/accel-pppd/ctrl/pppoe/mac_filter.c index ba78df6b..3a6a00d6 100644 --- a/accel-pppd/ctrl/pppoe/mac_filter.c +++ b/accel-pppd/ctrl/pppoe/mac_filter.c @@ -92,15 +92,17 @@ static int mac_filter_load(const char *opt) log_warn("pppoe: mac-filter:%s:%i: address is invalid\n", name, line); continue; } - mac = _malloc(sizeof(*mac)); for (i = 0; i < ETH_ALEN; i++) { - if (n[i] > 255) { - log_warn("pppoe: mac-filter:%s:%i: address is invalid\n", name, line); - _free(mac); - continue; - } - mac->addr[i] = n[i]; + if (n[i] > 255) + break; } + if (i < ETH_ALEN) { + log_warn("pppoe: mac-filter:%s:%i: address is invalid\n", name, line); + continue; + } + mac = _malloc(sizeof(*mac)); + for (i = 0; i < ETH_ALEN; i++) + mac->addr[i] = n[i]; list_add_tail(&mac->entry, &mac_list); } pthread_rwlock_unlock(&lock); diff --git a/accel-pppd/ctrl/pppoe/pppoe.c b/accel-pppd/ctrl/pppoe/pppoe.c index dd623acc..0cc23180 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.c +++ b/accel-pppd/ctrl/pppoe/pppoe.c @@ -11,11 +11,6 @@ #include <net/ethernet.h> #include <netpacket/packet.h> #include <arpa/inet.h> -#ifdef HAVE_PRINTF_H -#include <printf.h> -#endif - -#include "crypto.h" #include "events.h" #include "triton.h" @@ -48,6 +43,7 @@ struct pppoe_conn_t { struct pppoe_serv_t *serv; uint16_t sid; uint8_t addr[ETH_ALEN]; + unsigned int ppp_starting:1; unsigned int ppp_started:1; struct pppoe_tag *relay_sid; @@ -83,7 +79,7 @@ struct padi_t }; struct iplink_arg { - pcre *re; + pcre2_code *re; const char *opt; void *cli; long *arg1; @@ -114,17 +110,8 @@ static mempool_t conn_pool; static mempool_t pado_pool; static mempool_t padi_pool; -unsigned int stat_starting; -unsigned int stat_active; -unsigned int stat_delayed_pado; -unsigned long stat_PADI_recv; -unsigned long stat_PADI_drop; -unsigned long stat_PADO_sent; -unsigned long stat_PADR_recv; -unsigned long stat_PADR_dup_recv; -unsigned long stat_PADS_sent; +static struct pppoe_stat_t pppoe_stat; unsigned int total_padi_cnt; -unsigned long stat_filtered; pthread_rwlock_t serv_lock = PTHREAD_RWLOCK_INITIALIZER; LIST_HEAD(serv_list); @@ -136,6 +123,35 @@ static unsigned long *sid_map; static unsigned long *sid_ptr; static int sid_idx; +void __export pppoe_stat_get(struct pppoe_stat_t *stat) +{ + stat->starting = __atomic_load_n(&pppoe_stat.starting, __ATOMIC_RELAXED); + stat->active = __atomic_load_n(&pppoe_stat.active, __ATOMIC_RELAXED); + stat->delayed_PADO = __atomic_load_n(&pppoe_stat.delayed_PADO, __ATOMIC_RELAXED); + stat->PADI_recv = __atomic_load_n(&pppoe_stat.PADI_recv, __ATOMIC_RELAXED); + stat->PADI_drop = __atomic_load_n(&pppoe_stat.PADI_drop, __ATOMIC_RELAXED); + stat->PADO_sent = __atomic_load_n(&pppoe_stat.PADO_sent, __ATOMIC_RELAXED); + stat->PADR_recv = __atomic_load_n(&pppoe_stat.PADR_recv, __ATOMIC_RELAXED); + stat->PADR_dup_recv = __atomic_load_n(&pppoe_stat.PADR_dup_recv, __ATOMIC_RELAXED); + stat->PADS_sent = __atomic_load_n(&pppoe_stat.PADS_sent, __ATOMIC_RELAXED); + stat->filtered = __atomic_load_n(&pppoe_stat.filtered, __ATOMIC_RELAXED); +} + +unsigned int __export pppoe_stat_starting(void) +{ + return __atomic_load_n(&pppoe_stat.starting, __ATOMIC_RELAXED); +} + +unsigned int __export pppoe_stat_active(void) +{ + return __atomic_load_n(&pppoe_stat.active, __ATOMIC_RELAXED); +} + +void __export pppoe_stat_add_filtered(void) +{ + __atomic_add_fetch(&pppoe_stat.filtered, 1, __ATOMIC_RELAXED); +} + static uint8_t bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static void pppoe_send_PADT(struct pppoe_conn_t *conn); @@ -173,9 +189,12 @@ static void disconnect(struct pppoe_conn_t *conn) struct pppoe_serv_t *serv = conn->serv; if (conn->ppp_started) { - dpado_check_prev(__sync_fetch_and_sub(&stat_active, 1)); + dpado_check_prev(__atomic_fetch_sub(&pppoe_stat.active, 1, __ATOMIC_RELAXED)); conn->ppp_started = 0; ap_session_terminate(&conn->ppp.ses, TERM_USER_REQUEST, 1); + } else if (conn->ppp_starting) { + __atomic_sub_fetch(&pppoe_stat.starting, 1, __ATOMIC_RELAXED); + conn->ppp_starting = 0; } pppoe_send_PADT(conn); @@ -232,7 +251,7 @@ static void ppp_finished(struct ap_session *ses) log_ppp_debug("pppoe: ppp finished\n"); if (conn->ppp_started) { - dpado_check_prev(__sync_fetch_and_sub(&stat_active, 1)); + dpado_check_prev(__atomic_fetch_sub(&pppoe_stat.active, 1, __ATOMIC_RELAXED)); conn->ppp_started = 0; triton_context_call(&conn->ctx, (triton_event_func)disconnect, conn); } @@ -279,9 +298,15 @@ static void pppoe_conn_ctx_switch(struct triton_context_t *ctx, void *arg) static struct pppoe_conn_t *allocate_channel(struct pppoe_serv_t *serv, const uint8_t *addr, const struct pppoe_tag *host_uniq, const struct pppoe_tag *relay_sid, const struct pppoe_tag *service_name, const struct pppoe_tag *tr101, const uint8_t *cookie, uint16_t ppp_max_payload) { + struct pppoe_tag empty_service_name = { + .tag_type = htons(TAG_SERVICE_NAME), + }; struct pppoe_conn_t *conn; unsigned long *old_sid_ptr; + if (!service_name) + service_name = &empty_service_name; + conn = mempool_alloc(conn_pool); if (!conn) { log_error("pppoe: out of memory\n"); @@ -450,6 +475,9 @@ static void connect_channel(struct pppoe_conn_t *conn) struct sockaddr_pppox sp; triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); + conn->ppp_starting = 1; + __atomic_add_fetch(&pppoe_stat.starting, 1, __ATOMIC_RELAXED); + triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses); sock = net->socket(AF_PPPOX, SOCK_DGRAM, PX_PROTO_OE); @@ -486,9 +514,11 @@ static void connect_channel(struct pppoe_conn_t *conn) } #endif + conn->ppp_starting = 0; conn->ppp_started = 1; - dpado_check_next(__sync_add_and_fetch(&stat_active, 1)); + __atomic_sub_fetch(&pppoe_stat.starting, 1, __ATOMIC_RELAXED); + dpado_check_next(__atomic_add_fetch(&pppoe_stat.active, 1, __ATOMIC_RELAXED)); return; @@ -822,7 +852,7 @@ static void pppoe_send_PADO(struct pppoe_serv_t *serv, const uint8_t *addr, cons if (conf_verbose) print_packet(serv->ifname, "send", pack); - __sync_add_and_fetch(&stat_PADO_sent, 1); + __atomic_add_fetch(&pppoe_stat.PADO_sent, 1, __ATOMIC_RELAXED); pppoe_send(serv, pack); } @@ -871,7 +901,7 @@ static void pppoe_send_PADS(struct pppoe_conn_t *conn) if (conf_verbose) print_packet(conn->serv->ifname, "send", pack); - __sync_add_and_fetch(&stat_PADS_sent, 1); + __atomic_add_fetch(&pppoe_stat.PADS_sent, 1, __ATOMIC_RELAXED); pppoe_send(conn->serv, pack); } @@ -898,7 +928,7 @@ static void free_delayed_pado(struct delayed_pado_t *pado) { triton_timer_del(&pado->timer); - __sync_sub_and_fetch(&stat_delayed_pado, 1); + __atomic_sub_fetch(&pppoe_stat.delayed_PADO, 1, __ATOMIC_RELAXED); list_del(&pado->entry); if (pado->host_uniq) @@ -984,19 +1014,19 @@ static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size) struct timespec ts; uint16_t ppp_max_payload = 0; - __sync_add_and_fetch(&stat_PADI_recv, 1); + __atomic_add_fetch(&pppoe_stat.PADI_recv, 1, __ATOMIC_RELAXED); if (ap_shutdown || pado_delay == -1) return; - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) return; - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) return; if (check_padi_limit(serv, ethhdr->h_source)) { - __sync_add_and_fetch(&stat_PADI_drop, 1); + __atomic_add_fetch(&pppoe_stat.PADI_drop, 1, __ATOMIC_RELAXED); if (conf_verbose) { clock_gettime(CLOCK_MONOTONIC, &ts); if (ts.tv_sec - 60 >= serv->last_padi_limit_warn) { @@ -1017,7 +1047,7 @@ static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size) return; switch (ntohs(tag->tag_type)) { case TAG_END_OF_LIST: - break; + goto tags_done; case TAG_SERVICE_NAME: if (tag->tag_len == 0 && conf_accept_blank_service) { service_match = 1; @@ -1048,6 +1078,7 @@ static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size) break; } } +tags_done: if (conf_verbose) print_packet(serv->ifname, "recv", pack); @@ -1098,7 +1129,7 @@ static void pppoe_recv_PADI(struct pppoe_serv_t *serv, uint8_t *pack, int size) triton_timer_add(&serv->ctx, &pado->timer, 0); list_add_tail(&pado->entry, &serv->pado_list); - __sync_add_and_fetch(&stat_delayed_pado, 1); + __atomic_add_fetch(&pppoe_stat.delayed_PADO, 1, __ATOMIC_RELAXED); } else pppoe_send_PADO(serv, ethhdr->h_source, host_uniq_tag, relay_sid_tag, service_name_tag, ppp_max_payload); } @@ -1118,15 +1149,15 @@ static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size) int vendor_id; uint16_t ppp_max_payload = 0; - __sync_add_and_fetch(&stat_PADR_recv, 1); + __atomic_add_fetch(&pppoe_stat.PADR_recv, 1, __ATOMIC_RELAXED); if (ap_shutdown) return; - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) return; - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) return; if (!memcmp(ethhdr->h_dest, bc_addr, ETH_ALEN)) { @@ -1159,7 +1190,7 @@ static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size) } switch (ntohs(tag->tag_type)) { case TAG_END_OF_LIST: - break; + goto padr_tags_done; case TAG_SERVICE_NAME: service_name_tag = tag; if (tag->tag_len == 0) @@ -1194,12 +1225,14 @@ static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size) if (vendor_id == VENDOR_ADSL_FORUM) if (conf_tr101) tr101_tag = tag; + break; case TAG_PPP_MAX_PAYLOAD: if (ntohs(tag->tag_len) == 2) ppp_max_payload = ntohs(*(uint16_t *)tag->tag_data); break; } } +padr_tags_done: if (!ac_cookie_tag) { if (conf_verbose) @@ -1207,6 +1240,12 @@ static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size) return; } + if (!service_name_tag) { + if (conf_verbose) + log_warn("pppoe: discard PADR packet (no Service-Name tag present)\n"); + return; + } + if (ntohs(ac_cookie_tag->tag_len) != COOKIE_LENGTH) { if (conf_verbose) log_warn("pppoe: discard PADR packet (incorrect AC-Cookie tag length)\n"); @@ -1229,7 +1268,7 @@ static void pppoe_recv_PADR(struct pppoe_serv_t *serv, uint8_t *pack, int size) pthread_mutex_lock(&serv->lock); conn = find_channel(serv, (uint8_t *)ac_cookie_tag->tag_data); if (conn && !conn->ppp.ses.username) { - __sync_add_and_fetch(&stat_PADR_dup_recv, 1); + __atomic_add_fetch(&pppoe_stat.PADR_dup_recv, 1, __ATOMIC_RELAXED); pppoe_send_PADS(conn); } pthread_mutex_unlock(&serv->lock); @@ -1368,8 +1407,12 @@ out_err: static int __pppoe_add_interface_re(int index, int flags, const char *name, int iflink, int vid, struct iplink_arg *arg) { - if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0) + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + if (pcre2_match(arg->re, (PCRE2_SPTR)name, strlen(name), 0, 0, match_data, NULL) < 0) { + pcre2_match_data_free(match_data); return 0; + } + pcre2_match_data_free(match_data); __pppoe_server_start(name, arg->opt, arg->cli, iflink, vid, 0); @@ -1378,11 +1421,11 @@ static int __pppoe_add_interface_re(int index, int flags, const char *name, int static void pppoe_add_interface_re(const char *opt, void *cli) { - pcre *re = NULL; - const char *pcre_err; + pcre2_code *re = NULL; + int pcre_err; char *pattern; const char *ptr; - int pcre_offset; + PCRE2_SIZE pcre_offset; struct iplink_arg arg; for (ptr = opt; *ptr && *ptr != ','; ptr++); @@ -1391,10 +1434,14 @@ static void pppoe_add_interface_re(const char *opt, void *cli) memcpy(pattern, opt + 3, ptr - (opt + 3)); pattern[ptr - (opt + 3)] = 0; - re = pcre_compile2(pattern, 0, NULL, &pcre_err, &pcre_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, 0, &pcre_err, &pcre_offset, NULL); if (!re) { - log_error("pppoe: %s at %i\r\n", pcre_err, pcre_offset); + PCRE2_UCHAR err_msg[64]; + pcre2_get_error_message(pcre_err, err_msg, sizeof(err_msg)); + if (cli) + cli_sendv(cli, "pppoe: %s at %i\r\n", err_msg, (int)pcre_offset); + log_error("pppoe: %s at %i\r\n", err_msg, (int)pcre_offset); return; } @@ -1404,7 +1451,7 @@ static void pppoe_add_interface_re(const char *opt, void *cli) iplink_list((iplink_list_func)__pppoe_add_interface_re, &arg); - pcre_free(re); + pcre2_code_free(re); _free(pattern); } @@ -1637,12 +1684,6 @@ void pppoe_server_stop(const char *ifname) pthread_rwlock_unlock(&serv_lock); } -void __export pppoe_get_stat(unsigned int **starting, unsigned int **active) -{ - *starting = &stat_starting; - *active = &stat_active; -} - static int init_secret(struct pppoe_serv_t *serv) { DES_cblock key; @@ -1676,10 +1717,10 @@ void pppoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) struct ifreq ifr; char *ptr; int len, r, svid; - pcre *re = NULL; - const char *pcre_err; + pcre2_code *re = NULL; + int pcre_err; char *pattern; - int pcre_offset; + PCRE2_SIZE pcre_offset; char ifname[IFNAMSIZ]; if (!sect) @@ -1777,15 +1818,17 @@ void pppoe_vlan_mon_notify(int ifindex, int vid, int vlan_ifindex) memcpy(pattern, opt->val + 3, ptr - (opt->val + 3)); pattern[ptr - (opt->val + 3)] = 0; - re = pcre_compile2(pattern, 0, NULL, &pcre_err, &pcre_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, 0, &pcre_err, &pcre_offset, NULL); _free(pattern); if (!re) continue; - r = pcre_exec(re, NULL, ifr.ifr_name, len, 0, 0, NULL, 0); - pcre_free(re); + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + r = pcre2_match(re, (PCRE2_SPTR)ifr.ifr_name, len, 0, 0, match_data, NULL); + pcre2_match_data_free(match_data); + pcre2_code_free(re); if (r < 0) continue; @@ -1860,8 +1903,12 @@ static int __load_vlan_mon_re(int index, int flags, const char *name, int iflink long mask1[4096/8/sizeof(long)]; struct pppoe_serv_t *serv; - if (pcre_exec(arg->re, NULL, name, strlen(name), 0, 0, NULL, 0) < 0) + pcre2_match_data *match_data = pcre2_match_data_create(0, NULL); + if (pcre2_match(arg->re, (PCRE2_SPTR)name, strlen(name), 0, 0, match_data, NULL) < 0) { + pcre2_match_data_free(match_data); return 0; + } + pcre2_match_data_free(match_data); memset(&ifr, 0, sizeof(ifr)); strcpy(ifr.ifr_name, name); @@ -1894,11 +1941,11 @@ static int __load_vlan_mon_re(int index, int flags, const char *name, int iflink static void load_vlan_mon_re(const char *opt, long *mask, int len) { - pcre *re = NULL; - const char *pcre_err; + pcre2_code *re = NULL; + int pcre_err; char *pattern; const char *ptr; - int pcre_offset; + PCRE2_SIZE pcre_offset; struct iplink_arg arg; for (ptr = opt; *ptr && *ptr != ','; ptr++); @@ -1907,10 +1954,12 @@ static void load_vlan_mon_re(const char *opt, long *mask, int len) memcpy(pattern, opt + 3, ptr - (opt + 3)); pattern[ptr - (opt + 3)] = 0; - re = pcre_compile2(pattern, 0, NULL, &pcre_err, &pcre_offset, NULL); + re = pcre2_compile((PCRE2_SPTR)pattern, PCRE2_ZERO_TERMINATED, 0, &pcre_err, &pcre_offset, NULL); if (!re) { - log_error("pppoe: '%s': %s at %i\r\n", pattern, pcre_err, pcre_offset); + PCRE2_UCHAR err_msg[64]; + pcre2_get_error_message(pcre_err, err_msg, sizeof(err_msg)); + log_error("pppoe: '%s': %s at %i\r\n", pattern, err_msg, (int)pcre_offset); return; } @@ -1920,7 +1969,7 @@ static void load_vlan_mon_re(const char *opt, long *mask, int len) iplink_list((iplink_list_func)__load_vlan_mon_re, &arg); - pcre_free(re); + pcre2_code_free(re); _free(pattern); } diff --git a/accel-pppd/ctrl/pppoe/pppoe.h b/accel-pppd/ctrl/pppoe/pppoe.h index 7ba4ac63..42067590 100644 --- a/accel-pppd/ctrl/pppoe/pppoe.h +++ b/accel-pppd/ctrl/pppoe/pppoe.h @@ -6,8 +6,10 @@ #include <linux/if.h> #include <linux/if_pppox.h> +#include <openssl/md5.h> +#include <openssl/des.h> + #include "rbtree.h" -#include "crypto.h" /* PPPoE codes */ #define CODE_PADI 0x09 @@ -107,16 +109,24 @@ extern int conf_accept_any_service; extern char *conf_ac_name; extern char *conf_pado_delay; -extern unsigned int stat_starting; -extern unsigned int stat_active; -extern unsigned int stat_delayed_pado; -extern unsigned long stat_PADI_recv; -extern unsigned long stat_PADO_sent; -extern unsigned long stat_PADR_recv; -extern unsigned long stat_PADR_dup_recv; -extern unsigned long stat_PADS_sent; -extern unsigned long stat_PADI_drop; -extern unsigned long stat_filtered; +struct pppoe_stat_t +{ + unsigned int starting; + unsigned int active; + unsigned int delayed_PADO; + unsigned long PADI_recv; + unsigned long PADI_drop; + unsigned long PADO_sent; + unsigned long PADR_recv; + unsigned long PADR_dup_recv; + unsigned long PADS_sent; + unsigned long filtered; +}; + +void pppoe_stat_get(struct pppoe_stat_t *stat); +unsigned int pppoe_stat_starting(void); +unsigned int pppoe_stat_active(void); +void pppoe_stat_add_filtered(void); extern pthread_rwlock_t serv_lock; extern struct list_head serv_list; @@ -140,4 +150,3 @@ int tr101_send_access_request(struct pppoe_tag *tr101, struct rad_packet_t *pack int tr101_send_accounting_request(struct pppoe_tag *tr101, struct rad_packet_t *pack); #endif - diff --git a/accel-pppd/ctrl/pptp/pptp.c b/accel-pppd/ctrl/pptp/pptp.c index a95fe8ae..f8e498d6 100644 --- a/accel-pppd/ctrl/pptp/pptp.c +++ b/accel-pppd/ctrl/pptp/pptp.c @@ -25,6 +25,7 @@ #include "cli.h" #include "connlimit.h" +#include "pptp.h" #include "memdebug.h" @@ -55,6 +56,19 @@ struct pptp_conn_t struct ppp_t ppp; }; +struct pptp_stat_t +{ + unsigned int starting; + unsigned int active; +}; + +struct pptp_serv_t +{ + struct triton_context_t ctx; + struct triton_md_handler_t hnd; + struct pptp_stat_t stat; +}; + static int conf_ppp_max_mtu = PPTP_MAX_MTU; static int conf_timeout = 5; static int conf_echo_interval = 0; @@ -69,14 +83,53 @@ static const char *conf_ifname; static mempool_t conn_pool; -static unsigned int stat_starting; -static unsigned int stat_active; - static int pptp_read(struct triton_md_handler_t *h); static int pptp_write(struct triton_md_handler_t *h); static void pptp_timeout(struct triton_timer_t *); static void ppp_started(struct ap_session *); static void ppp_finished(struct ap_session *); +static void pptp_ctx_switch(struct triton_context_t *ctx, void *arg); +static int pptp_connect(struct triton_md_handler_t *h); +static void pptp_serv_close(struct triton_context_t *ctx); + +static struct pptp_serv_t serv = +{ + .hnd.read = pptp_connect, + .ctx.close = pptp_serv_close, + .ctx.before_switch = pptp_ctx_switch, +}; + +static void pptp_stat_inc(unsigned int *stat) +{ + __atomic_add_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void pptp_stat_dec(unsigned int *stat) +{ + __atomic_sub_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void pptp_stat_move(unsigned int *from, unsigned int *to) +{ + pptp_stat_dec(from); + pptp_stat_inc(to); +} + +static void pptp_stat_get(struct pptp_stat_t *stat) +{ + stat->starting = __atomic_load_n(&serv.stat.starting, __ATOMIC_RELAXED); + stat->active = __atomic_load_n(&serv.stat.active, __ATOMIC_RELAXED); +} + +unsigned int __export pptp_stat_starting(void) +{ + return __atomic_load_n(&serv.stat.starting, __ATOMIC_RELAXED); +} + +unsigned int __export pptp_stat_active(void) +{ + return __atomic_load_n(&serv.stat.active, __ATOMIC_RELAXED); +} static void pptp_ctx_switch(struct triton_context_t *ctx, void *arg) { @@ -101,11 +154,11 @@ static void disconnect(struct pptp_conn_t *conn) triton_timer_del(&conn->echo_timer); if (conn->state == STATE_PPP) { - __sync_sub_and_fetch(&stat_active, 1); + pptp_stat_dec(&serv.stat.active); conn->state = STATE_CLOSE; ap_session_terminate(&conn->ppp.ses, TERM_LOST_CARRIER, 1); } else if (conn->state != STATE_CLOSE) - __sync_sub_and_fetch(&stat_starting, 1); + pptp_stat_dec(&serv.stat.starting); triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); @@ -142,8 +195,8 @@ again: if (errno != EPIPE) { if (conf_verbose) log_ppp_info2("pptp: write: %s\n", strerror(errno)); - return -1; } + return -1; } } @@ -356,8 +409,7 @@ static int pptp_out_call_rqst(struct pptp_conn_t *conn) return -1; } conn->state = STATE_PPP; - __sync_sub_and_fetch(&stat_starting, 1); - __sync_add_and_fetch(&stat_active, 1); + pptp_stat_move(&serv.stat.starting, &serv.stat.active); if (conn->timeout_timer.tpd) triton_timer_del(&conn->timeout_timer); @@ -397,7 +449,7 @@ static int pptp_call_clear_rqst(struct pptp_conn_t *conn) triton_timer_del(&conn->echo_timer); if (conn->state == STATE_PPP) { - __sync_sub_and_fetch(&stat_active, 1); + pptp_stat_dec(&serv.stat.active); conn->state = STATE_CLOSE; ap_session_terminate(&conn->ppp.ses, TERM_USER_REQUEST, 1); } @@ -578,7 +630,7 @@ static void pptp_close(struct triton_context_t *ctx) { struct pptp_conn_t *conn = container_of(ctx, typeof(*conn), ctx); if (conn->state == STATE_PPP) { - __sync_sub_and_fetch(&stat_active, 1); + pptp_stat_dec(&serv.stat.active); conn->state = STATE_CLOSE; ap_session_terminate(&conn->ppp.ses, TERM_ADMIN_RESET, 1); if (send_pptp_call_disconnect_notify(conn, 3)) { @@ -609,7 +661,7 @@ static void ppp_finished(struct ap_session *ses) if (conn->state != STATE_CLOSE) { log_ppp_debug("pptp: ppp finished\n"); conn->state = STATE_CLOSE; - __sync_sub_and_fetch(&stat_active, 1); + pptp_stat_dec(&serv.stat.active); if (send_pptp_call_disconnect_notify(conn, 3)) triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn); @@ -626,12 +678,6 @@ static void ppp_finished(struct ap_session *ses) //================================== -struct pptp_serv_t -{ - struct triton_context_t ctx; - struct triton_md_handler_t hnd; -}; - static int pptp_connect(struct triton_md_handler_t *h) { struct sockaddr_in addr; @@ -653,12 +699,12 @@ static int pptp_connect(struct triton_md_handler_t *h) continue; } - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) { + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) { close(sock); continue; } - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) { + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) { close(sock); continue; } @@ -708,7 +754,7 @@ static int pptp_connect(struct triton_md_handler_t *h) conn->ctrl.calling_station_id = _malloc(17); conn->ctrl.called_station_id = _malloc(17); u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.calling_station_id); - getsockname(sock, &addr, &size); + getsockname(sock, (struct sockaddr*)&addr, &size); u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.called_station_id); ppp_init(&conn->ppp); @@ -733,7 +779,7 @@ static int pptp_connect(struct triton_md_handler_t *h) triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); - __sync_add_and_fetch(&stat_starting, 1); + pptp_stat_inc(&serv.stat.starting); } return 0; } @@ -744,28 +790,19 @@ static void pptp_serv_close(struct triton_context_t *ctx) triton_context_unregister(ctx); } -static struct pptp_serv_t serv= -{ - .hnd.read = pptp_connect, - .ctx.close = pptp_serv_close, - .ctx.before_switch = pptp_ctx_switch, -}; - static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) { + struct pptp_stat_t stat; + + pptp_stat_get(&stat); + cli_send(client, "pptp:\r\n"); - cli_sendv(client," starting: %u\r\n", stat_starting); - cli_sendv(client," active: %u\r\n", stat_active); + cli_sendv(client," starting: %u\r\n", stat.starting); + cli_sendv(client," active: %u\r\n", stat.active); return CLI_CMD_OK; } -void __export pptp_get_stat(unsigned int **starting, unsigned int **active) -{ - *starting = &stat_starting; - *active = &stat_active; -} - static void load_config(void) { char *opt; diff --git a/accel-pppd/ctrl/pptp/pptp.h b/accel-pppd/ctrl/pptp/pptp.h new file mode 100644 index 00000000..29f24ca2 --- /dev/null +++ b/accel-pppd/ctrl/pptp/pptp.h @@ -0,0 +1,7 @@ +#ifndef __PPTP_H +#define __PPTP_H + +unsigned int pptp_stat_starting(void); +unsigned int pptp_stat_active(void); + +#endif diff --git a/accel-pppd/ctrl/sstp/CMakeLists.txt b/accel-pppd/ctrl/sstp/CMakeLists.txt index 3cb1799c..3a79526f 100644 --- a/accel-pppd/ctrl/sstp/CMakeLists.txt +++ b/accel-pppd/ctrl/sstp/CMakeLists.txt @@ -2,6 +2,6 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ADD_LIBRARY(sstp SHARED sstp.c) -TARGET_LINK_LIBRARIES(sstp util) +TARGET_LINK_LIBRARIES(sstp util ${crypto_lib}) INSTALL(TARGETS sstp LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp) diff --git a/accel-pppd/ctrl/sstp/sstp.c b/accel-pppd/ctrl/sstp/sstp.c index 2e2c4d3b..6c2b9ca9 100644 --- a/accel-pppd/ctrl/sstp/sstp.c +++ b/accel-pppd/ctrl/sstp/sstp.c @@ -19,10 +19,13 @@ #include <sys/stat.h> #include "linux_ppp.h" -#ifdef CRYPTO_OPENSSL +/* + * Suppress OpenSSL 3.0 deprecation warnings for DH API. + * See crypto.h for detailed explanation. + */ +#define OPENSSL_API_COMPAT 0x10100000L #include <openssl/ssl.h> -#include <openssl/err.h> -#endif +#include <openssl/err.h> #include "triton.h" #include "events.h" @@ -38,6 +41,7 @@ #include "memdebug.h" #include "proxy_prot.h" +#include "sstp.h" #include "sstp_prot.h" #ifndef min @@ -102,9 +106,7 @@ struct buffer_t { struct sstp_stream_t { union { int fd; -#ifdef CRYPTO_OPENSSL SSL *ssl; -#endif }; ssize_t (*read)(struct sstp_stream_t *stream, void *buf, size_t count); ssize_t (*recv)(struct sstp_stream_t *stream, void *buf, size_t count, int flags); @@ -147,16 +149,17 @@ struct sstp_conn_t { struct ap_ctrl ctrl; }; -static struct sstp_serv_t { +struct sstp_serv_t { struct triton_context_t ctx; struct triton_md_handler_t hnd; struct sockaddr_t addr; -#ifdef CRYPTO_OPENSSL SSL_CTX *ssl_ctx; -#endif -} serv; + struct sstp_stat_t stat; +}; + +static struct sstp_serv_t serv; static int conf_timeout = SSTP_NEGOTIOATION_TIMEOUT; static int conf_hello_interval = SSTP_HELLO_TIMEOUT; @@ -176,23 +179,59 @@ static struct hash_t conf_hash_sha1 = { .len = 0 }; static struct hash_t conf_hash_sha256 = { .len = 0 }; //static int conf_bypass_auth = 0; static const char *conf_hostname = NULL; -static int conf_http_mode = -1; +enum { + HTTP_ERR_ALLOW = -1, + HTTP_ERR_DENY = 0, + HTTP_ERR_REDIRECT = 1, + HTTP_ERR_REDIRECT_APPEND = 2, +}; +static int conf_http_mode = HTTP_ERR_ALLOW; static const char *conf_http_url = NULL; static mempool_t conn_pool; -static unsigned int stat_starting; -static unsigned int stat_active; - static inline void sstp_queue(struct sstp_conn_t *conn, struct buffer_t *buf); static int sstp_send(struct sstp_conn_t *conn, struct buffer_t *buf); static inline void sstp_queue_deferred(struct sstp_conn_t *conn, struct buffer_t *buf); +static int sstp_write(struct triton_md_handler_t *h); static int sstp_read_deferred(struct sstp_conn_t *conn); static int sstp_abort(struct sstp_conn_t *conn, int disconnect); static void sstp_disconnect(struct sstp_conn_t *conn); static int sstp_handler(struct sstp_conn_t *conn, struct buffer_t *buf); static int http_handler(struct sstp_conn_t *conn, struct buffer_t *buf); +void __export sstp_stat_get(struct sstp_stat_t *stat) +{ + stat->starting = __atomic_load_n(&serv.stat.starting, __ATOMIC_RELAXED); + stat->active = __atomic_load_n(&serv.stat.active, __ATOMIC_RELAXED); +} + +unsigned int __export sstp_stat_starting(void) +{ + return __atomic_load_n(&serv.stat.starting, __ATOMIC_RELAXED); +} + +unsigned int __export sstp_stat_active(void) +{ + return __atomic_load_n(&serv.stat.active, __ATOMIC_RELAXED); +} + +static void sstp_stat_inc(unsigned int *stat) +{ + __atomic_add_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void sstp_stat_dec(unsigned int *stat) +{ + __atomic_sub_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void sstp_stat_move(unsigned int *from, unsigned int *to) +{ + sstp_stat_dec(from); + sstp_stat_inc(to); +} + /* * FCS lookup table as calculated by genfcstab. */ @@ -489,7 +528,6 @@ static struct sstp_stream_t *stream_init(int fd) /* ssl stream */ -#ifdef CRYPTO_OPENSSL static ssize_t ssl_stream_read(struct sstp_stream_t *stream, void *buf, size_t count) { int ret, err; @@ -585,7 +623,6 @@ error: ssl_stream_free(stream); return NULL; } -#endif /* proxy */ @@ -858,7 +895,7 @@ static int http_send_response(struct sstp_conn_t *conn, char *proto, char *statu } } - return sstp_send(conn, buf); + return sstp_send(conn, buf) || sstp_write(&conn->hnd); } static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) @@ -879,17 +916,17 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) log_ppp_info2("recv [HTTP <%s>]\n", line); if (vstrsep(line, " ", &method, &request, &proto) < 3) { - if (conf_http_mode) + if (conf_http_mode != HTTP_ERR_DENY) http_send_response(conn, "HTTP/1.1", "400 Bad Request", NULL); return -1; } if (strncasecmp(proto, "HTTP/1", sizeof("HTTP/1") - 1) != 0) { - if (conf_http_mode) + if (conf_http_mode != HTTP_ERR_DENY) http_send_response(conn, "HTTP/1.1", "400 Bad Request", NULL); return -1; } if (strcasecmp(method, SSTP_HTTP_METHOD) != 0 && strcasecmp(method, "GET") != 0) { - if (conf_http_mode) + if (conf_http_mode != HTTP_ERR_DENY) http_send_response(conn, proto, "501 Not Implemented", NULL); return -1; } @@ -911,7 +948,7 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) } if (host_error) { - if (conf_http_mode) + if (conf_http_mode != HTTP_ERR_DENY) http_send_response(conn, proto, "404 Not Found", NULL); return -1; } @@ -919,11 +956,11 @@ static int http_recv_request(struct sstp_conn_t *conn, uint8_t *data, int len) if (strcasecmp(method, SSTP_HTTP_METHOD) != 0 || strcasecmp(request, SSTP_HTTP_URI) != 0) { if (conf_http_mode > 0) { if (_asprintf(&line, "Location: %s%s\r\n", - conf_http_url, (conf_http_mode == 2) ? request : "") < 0) + conf_http_url, (conf_http_mode == HTTP_ERR_REDIRECT_APPEND) ? request : "") < 0) return -1; http_send_response(conn, proto, "301 Moved Permanently", line); _free(line); - } else if (conf_http_mode < 0) + } else if (conf_http_mode == HTTP_ERR_ALLOW) http_send_response(conn, proto, "404 Not Found", NULL); return -1; } @@ -937,7 +974,7 @@ static int http_handler(struct sstp_conn_t *conn, struct buffer_t *buf) static const char *table[] = { "\n\r\n", "\r\r\n", NULL }; const char **pptr; uint8_t *ptr, *end = NULL; - int n; + int n, r; if (conn->sstp_state != STATE_SERVER_CALL_DISCONNECTED) return -1; @@ -963,8 +1000,11 @@ static int http_handler(struct sstp_conn_t *conn, struct buffer_t *buf) } else n = end - buf->head; - if (http_recv_request(conn, buf->head, n) < 0) + r = http_recv_request(conn, buf->head, n); + if (r < 0) return -1; + else if (r > 0) + return 1; buf_pull(buf, n); conn->sstp_state = STATE_SERVER_CONNECT_REQUEST_PENDING; @@ -1200,7 +1240,7 @@ static int ppp_write(struct triton_md_handler_t *h) ssize_t n; int i; - if (!list_empty(&conn->ppp_queue)) { + while (!list_empty(&conn->ppp_queue)) { i = n = 0; list_for_each_entry(buf, &conn->ppp_queue, entry) { if (i < PPP_BUF_IOVEC && n < PPP_BUF_SIZE) { @@ -1232,9 +1272,6 @@ static int ppp_write(struct triton_md_handler_t *h) list_del(&buf->entry); free_buf(buf); } while (n > 0); - - if (!list_empty(&conn->ppp_queue)) - goto defer; } triton_md_disable_handler(h, MD_MODE_WRITE); return 0; @@ -1500,8 +1537,7 @@ static int sstp_recv_msg_call_connect_request(struct sstp_conn_t *conn, struct s goto error; conn->sstp_state = STATE_SERVER_CALL_CONNECTED_PENDING; - __sync_sub_and_fetch(&stat_starting, 1); - __sync_add_and_fetch(&stat_active, 1); + sstp_stat_move(&serv.stat.starting, &serv.stat.active); triton_event_fire(EV_CTRL_STARTED, &conn->ppp.ses); conn->ppp_state = STATE_STARTING; @@ -1528,12 +1564,10 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct uint8_t hash; unsigned int len; struct npioctl np; -#ifdef CRYPTO_OPENSSL typeof(*msg) buf; uint8_t md[EVP_MAX_MD_SIZE], *ptr; const EVP_MD *evp; unsigned int mdlen; -#endif if (conf_verbose) log_ppp_info2("recv [SSTP SSTP_MSG_CALL_CONNECTED]\n"); @@ -1571,9 +1605,7 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct log_ppp_error("sstp: invalid SHA256 Cert Hash\n"); return sstp_abort(conn, 0); } -#ifdef CRYPTO_OPENSSL evp = EVP_sha256(); -#endif } else if (hash & CERT_HASH_PROTOCOL_SHA1) { len = SHA_DIGEST_LENGTH; if (conf_hash_sha1.len == len && @@ -1581,9 +1613,7 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct log_ppp_error("sstp: invalid SHA1 Cert Hash\n"); return sstp_abort(conn, 0); } -#ifdef CRYPTO_OPENSSL evp = EVP_sha1(); -#endif } else { log_ppp_error("sstp: invalid Hash Protocol 0x%02x\n", msg->attr.hash_protocol_bitmask); @@ -1608,7 +1638,6 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct return 0; } -#ifdef CRYPTO_OPENSSL ptr = mempcpy(md, SSTP_CMK_SEED, SSTP_CMK_SEED_SIZE); *ptr++ = len; *ptr++ = 0; @@ -1624,7 +1653,6 @@ static int sstp_recv_msg_call_connected(struct sstp_conn_t *conn, struct sstp_ct log_ppp_error("sstp: invalid Compound MAC\n"); return sstp_abort(conn, 0); } -#endif } if (conn->timeout_timer.tpd) @@ -1818,7 +1846,7 @@ static int sstp_recv_data_packet(struct sstp_conn_t *conn, struct sstp_hdr *hdr) buf_put_data(buf, hdr->data, size); #else - buf = alloc_buf(size*2 + 2 + PPP_FCSLEN); + buf = alloc_buf(size*2 + 2 + PPP_FCSLEN*2); if (!buf) { log_error("sstp: no memory\n"); return -1; @@ -1950,6 +1978,8 @@ static int sstp_read(struct triton_md_handler_t *h) n = conn->handler(conn, buf); if (n < 0) goto drop; + else if (n > 0) + return 1; buf_expand_tail(buf, SSTP_MAX_PACKET_SIZE); } @@ -2208,17 +2238,17 @@ static void sstp_disconnect(struct sstp_conn_t *conn) switch (conn->ppp_state) { case STATE_INIT: - __sync_sub_and_fetch(&stat_starting, 1); + sstp_stat_dec(&serv.stat.starting); break; case STATE_STARTING: case STATE_AUTHORIZED: case STATE_STARTED: conn->ppp_state = STATE_FINISHED; - __sync_sub_and_fetch(&stat_active, 1); + sstp_stat_dec(&serv.stat.active); ap_session_terminate(&conn->ppp.ses, TERM_LOST_CARRIER, 1); break; case STATE_FINISHED: - __sync_sub_and_fetch(&stat_active, 1); + sstp_stat_dec(&serv.stat.active); break; } triton_event_fire(EV_CTRL_FINISHED, &conn->ppp.ses); @@ -2254,11 +2284,9 @@ static void sstp_start(struct sstp_conn_t *conn) { log_debug("sstp: starting\n"); -#ifdef CRYPTO_OPENSSL if (serv.ssl_ctx) conn->stream = ssl_stream_init(conn->hnd.fd, serv.ssl_ctx); else -#endif conn->stream = stream_init(conn->hnd.fd); if (!conn->stream) { log_error("sstp: stream open error: %s\n", strerror(errno)); @@ -2299,12 +2327,12 @@ static int sstp_connect(struct triton_md_handler_t *h) continue; } - if (conf_max_starting && ap_session_stat.starting >= conf_max_starting) { + if (conf_max_starting && ap_session_stat_starting() >= conf_max_starting) { close(sock); continue; } - if (conf_max_sessions && ap_session_stat.active + ap_session_stat.starting >= conf_max_sessions) { + if (conf_max_sessions && ap_session_stat_active() + ap_session_stat_starting() >= conf_max_sessions) { close(sock); continue; } @@ -2425,7 +2453,7 @@ static int sstp_connect(struct triton_md_handler_t *h) triton_event_fire(EV_CTRL_STARTING, &conn->ppp.ses); - __sync_add_and_fetch(&stat_starting, 1); + sstp_stat_inc(&serv.stat.starting); } return 0; @@ -2438,17 +2466,14 @@ static void sstp_serv_close(struct triton_context_t *ctx) triton_md_unregister_handler(&serv->hnd, 1); triton_context_unregister(ctx); -#ifdef CRYPTO_OPENSSL if (serv->ssl_ctx) SSL_CTX_free(serv->ssl_ctx); serv->ssl_ctx = NULL; -#endif if (serv->addr.u.sa.sa_family == AF_UNIX && serv->addr.u.sun.sun_path[0]) unlink(serv->addr.u.sun.sun_path); } -#ifdef CRYPTO_OPENSSL #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME static int ssl_servername(SSL *ssl, int *al, void *arg) { @@ -2482,6 +2507,13 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret) #endif #endif +static void ssl_set_cert_hashes(const X509 *cert) { + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) + X509_digest(cert, EVP_sha1(), conf_hash_sha1.hash, &conf_hash_sha1.len); + if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) + X509_digest(cert, EVP_sha256(), conf_hash_sha256.hash, &conf_hash_sha256.len); +} + static void ssl_load_config(struct sstp_serv_t *serv, const char *servername) { SSL_CTX *old_ctx, *ssl_ctx = NULL; @@ -2489,26 +2521,6 @@ static void ssl_load_config(struct sstp_serv_t *serv, const char *servername) BIO *in = NULL; char *opt; - opt = conf_get_opt("sstp", "ssl-pemfile"); - if (opt) { - in = BIO_new(BIO_s_file()); - if (!in) { - log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - - if (BIO_read_filename(in, opt) <= 0) { - log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - - cert = PEM_read_bio_X509(in, NULL, NULL, NULL); - if (!cert) { - log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); - goto error; - } - } - opt = conf_get_opt("sstp", "accept"); if (opt && strhas(opt, "ssl", ',')) { legacy_ssl: @@ -2601,6 +2613,8 @@ static void ssl_load_config(struct sstp_serv_t *serv, const char *servername) #else DH *dh; + in = BIO_new(BIO_s_file()); + if (BIO_read_filename(in, opt) <= 0) { log_error("sstp: %s error: %s\n", "ssl-dhparam", ERR_error_string(ERR_get_error(), NULL)); goto error; @@ -2612,6 +2626,10 @@ static void ssl_load_config(struct sstp_serv_t *serv, const char *servername) goto error; } + if (!BIO_free(in)) + abort(); + in = NULL; + SSL_CTX_set_tmp_dh(ssl_ctx, dh); DH_free(dh); #endif @@ -2664,12 +2682,21 @@ static void ssl_load_config(struct sstp_serv_t *serv, const char *servername) if (opt && atoi(opt)) SSL_CTX_set_options(ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - if (cert && SSL_CTX_use_certificate(ssl_ctx, cert) != 1) { - log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); - goto error; + opt = conf_get_opt("sstp", "ssl-pemfile"); + if (opt) { + if (SSL_CTX_use_certificate_chain_file(ssl_ctx, opt) != 1) { + log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + // cert is a reference. Do not free it. + X509 *cert_ref = SSL_CTX_get0_certificate(ssl_ctx); + if (!cert_ref) { + log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + ssl_set_cert_hashes(cert_ref); } - - opt = conf_get_opt("sstp", "ssl-keyfile") ? : conf_get_opt("sstp", "ssl-pemfile"); + opt = conf_get_opt("sstp", "ssl-keyfile") ? : opt; if ((opt && SSL_CTX_use_PrivateKey_file(ssl_ctx, opt, SSL_FILETYPE_PEM) != 1) || SSL_CTX_check_private_key(ssl_ctx) != 1) { log_error("sstp: %s error: %s\n", "ssl-keyfile", ERR_error_string(ERR_get_error(), NULL)); @@ -2697,13 +2724,30 @@ static void ssl_load_config(struct sstp_serv_t *serv, const char *servername) opt = conf_get_opt("sstp", "ssl"); if (opt && atoi(opt) > 0) goto legacy_ssl; - } - if (cert) { - if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA1) - X509_digest(cert, EVP_sha1(), conf_hash_sha1.hash, &conf_hash_sha1.len); - if (conf_hash_protocol & CERT_HASH_PROTOCOL_SHA256) - X509_digest(cert, EVP_sha256(), conf_hash_sha256.hash, &conf_hash_sha256.len); + opt = conf_get_opt("sstp", "ssl-pemfile"); + if (opt) { + in = BIO_new(BIO_s_file()); + if (!in) { + log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + if (BIO_read_filename(in, opt) <= 0) { + log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + + cert = PEM_read_bio_X509(in, NULL, NULL, NULL); + if (!cert) { + log_error("sstp: %s error: %s\n", "ssl-pemfile", ERR_error_string(ERR_get_error(), NULL)); + goto error; + } + if (!BIO_free(in)) + abort(); + in = NULL; + ssl_set_cert_hashes(cert); + } } old_ctx = serv->ssl_ctx; @@ -2715,10 +2759,9 @@ error: SSL_CTX_free(ssl_ctx); if (cert) X509_free(cert); - if (in) - BIO_free(in); + if (in && !BIO_free(in)) + abort(); } -#endif static void ev_mppe_keys(struct ev_mppe_keys_t *ev) { @@ -2752,19 +2795,17 @@ static void ev_ses_authorized(struct ap_session *ses) static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) { + struct sstp_stat_t stat; + + sstp_stat_get(&stat); + cli_send(client, "sstp:\r\n"); - cli_sendv(client," starting: %u\r\n", stat_starting); - cli_sendv(client," active: %u\r\n", stat_active); + cli_sendv(client," starting: %u\r\n", stat.starting); + cli_sendv(client," active: %u\r\n", stat.active); return CLI_CMD_OK; } -void __export sstp_get_stat(unsigned int **starting, unsigned int **active) -{ - *starting = &stat_starting; - *active = &stat_active; -} - static void load_config(void) { int ipmode; @@ -2779,15 +2820,15 @@ static void load_config(void) opt = conf_get_opt("sstp", "http-error"); if (opt) { if (strcmp(opt, "deny") == 0) - conf_http_mode = 0; + conf_http_mode = HTTP_ERR_DENY; else if (strcmp(opt, "allow") == 0) - conf_http_mode = -1; + conf_http_mode = HTTP_ERR_ALLOW; else if (strstr(opt, "://") != NULL) { conf_http_url = opt; opt = strstr(opt, "://") + 3; while (*opt == '/') opt++; - conf_http_mode = strchr(opt, '/') ? 1 : 2; + conf_http_mode = strchr(opt, '/') ? HTTP_ERR_REDIRECT : HTTP_ERR_REDIRECT_APPEND; } } @@ -2803,12 +2844,9 @@ static void load_config(void) opt = conf_get_opt("sstp", "accept"); conf_proxyproto = opt && strhas(opt, "proxy", ','); -#ifdef CRYPTO_OPENSSL ssl_load_config(&serv, conf_hostname); opt = serv.ssl_ctx ? "enabled" : "disabled"; -#else - opt = "not available"; -#endif + if (conf_verbose) { log_info2("sstp: SSL/TLS support %s, PROXY support %s\n", opt, conf_proxyproto ? "enabled" : "disabled"); diff --git a/accel-pppd/ctrl/sstp/sstp.h b/accel-pppd/ctrl/sstp/sstp.h new file mode 100644 index 00000000..eff8e053 --- /dev/null +++ b/accel-pppd/ctrl/sstp/sstp.h @@ -0,0 +1,14 @@ +#ifndef __SSTP_H +#define __SSTP_H + +struct sstp_stat_t +{ + unsigned int starting; + unsigned int active; +}; + +void sstp_stat_get(struct sstp_stat_t *stat); +unsigned int sstp_stat_starting(void); +unsigned int sstp_stat_active(void); + +#endif diff --git a/accel-pppd/extra/CMakeLists.txt b/accel-pppd/extra/CMakeLists.txt index 6badcd5e..08466f24 100644 --- a/accel-pppd/extra/CMakeLists.txt +++ b/accel-pppd/extra/CMakeLists.txt @@ -5,11 +5,13 @@ set_property(TARGET pppd_compat PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/l ADD_LIBRARY(ippool SHARED ippool.c) ADD_LIBRARY(ipv6pool SHARED ipv6pool.c) ADD_LIBRARY(chap-secrets SHARED chap-secrets.c) +TARGET_LINK_LIBRARIES(chap-secrets ${crypto_lib}) ADD_LIBRARY(logwtmp SHARED logwtmp.c) TARGET_LINK_LIBRARIES(logwtmp util) ADD_LIBRARY(connlimit SHARED connlimit.c) +ADD_LIBRARY(metrics SHARED metrics.c) -INSTALL(TARGETS pppd_compat ippool ipv6pool sigchld chap-secrets logwtmp connlimit +INSTALL(TARGETS pppd_compat ippool ipv6pool sigchld chap-secrets logwtmp connlimit metrics LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp ) diff --git a/accel-pppd/extra/bitpool.h b/accel-pppd/extra/bitpool.h new file mode 100644 index 00000000..fa739a28 --- /dev/null +++ b/accel-pppd/extra/bitpool.h @@ -0,0 +1,88 @@ +#ifndef __BITPOOL_H +#define __BITPOOL_H + +#include <stdint.h> +#include <stddef.h> + +/* + * Fixed-size bit array shared by the IPv4/IPv6 address pool allocators. + * + * Semantics: bit == 1 => allocated/unavailable, bit == 0 => free. A freshly + * calloc'd map is therefore all-free. The caller is responsible for pre-setting + * to 1 any bit it never wants handed out: + * - "remainder" bits in the final word (indices >= count), and + * - reserved in-range bits (e.g. the p2p gateway collision), + * so the word-at-a-time scan can never return a non-existent unit. + */ + +typedef unsigned long bm_word_t; +#define BM_WORD_BITS (8 * sizeof(bm_word_t)) +#define BM_NWORDS(n) (((n) + BM_WORD_BITS - 1) / BM_WORD_BITS) +#define BM_INVALID ((uint64_t)-1) + +static inline void bm_set(bm_word_t *bm, uint64_t i) +{ + bm[i / BM_WORD_BITS] |= (bm_word_t)1 << (i % BM_WORD_BITS); +} + +static inline void bm_clear(bm_word_t *bm, uint64_t i) +{ + bm[i / BM_WORD_BITS] &= ~((bm_word_t)1 << (i % BM_WORD_BITS)); +} + +static inline int bm_test(const bm_word_t *bm, uint64_t i) +{ + return (bm[i / BM_WORD_BITS] >> (i % BM_WORD_BITS)) & 1; +} + +/* + * Find the first free (0) bit at or after `from`, wrapping once back to 0. + * `count` is the number of valid bits; remainder bits in the final word must + * already be set to 1 by the caller so they are never returned. Returns the + * bit index in [0,count), or BM_INVALID if every bit is used. + * + * Word-at-a-time: a fully-used word (~w == 0) is skipped in one branch, so the + * scan is O(1) amortized for a sparse pool and O(count/word) worst case. + */ +static inline uint64_t bm_find_free(const bm_word_t *bm, uint64_t count, uint64_t from) +{ + uint64_t nwords, fw, i; + unsigned fb; + + if (!count) + return BM_INVALID; + if (from >= count) + from = 0; + + nwords = BM_NWORDS(count); + fw = from / BM_WORD_BITS; + fb = from % BM_WORD_BITS; + + /* Probe nwords+1 times: the start word is examined first with its low bits + * (< from) masked off, and once more at the end with only those low bits, + * so every bit is considered exactly once across the wrap. */ + for (i = 0; i <= nwords; i++) { + uint64_t word = fw + i; + bm_word_t inv; + + if (word >= nwords) + word -= nwords; + + inv = ~bm[word]; + + if (i == 0) + inv &= ~(((bm_word_t)1 << fb) - 1); /* skip bits below `from` */ + else if (i == nwords) + inv &= ((bm_word_t)1 << fb) - 1; /* wrapped: only those skipped bits */ + + if (inv) { + uint64_t bit = word * BM_WORD_BITS + __builtin_ctzl(inv); + if (bit < count) + return bit; + } + } + + return BM_INVALID; +} + +#endif diff --git a/accel-pppd/extra/bitpool_test.c b/accel-pppd/extra/bitpool_test.c new file mode 100644 index 00000000..347f1770 --- /dev/null +++ b/accel-pppd/extra/bitpool_test.c @@ -0,0 +1,256 @@ +/* + * Standalone sanity test for the bitmap IP-pool allocator core. + * + * Not part of the cmake build. Compile and run with: + * gcc -O2 -Wall -o /tmp/bitpool_test accel-pppd/extra/bitpool_test.c && /tmp/bitpool_test + * + * It validates: + * - bitpool.h: bm_set/clear/test, bm_find_free wrap + remainder bits + + * exhaustion, and that every freed bit is re-handed exactly once. + * - IPv4 addr<->bit round-trip for p2p and net30 geometry, incl. alignment + * and out-of-range rejection. + * - IPv6 prefix<->bit round-trip (the exact helpers used by ipv6pool.c), + * cross-checked against __int128 reference math, incl. prefix_len==128, + * mask<=64 / mask>64, and an unaligned base. + */ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <assert.h> + +#include "bitpool.h" + +static int failures; +#define CHECK(cond) do { if (!(cond)) { \ + fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); failures++; } } while (0) + +/* ---- mimic a finalized range bitmap: count bits free, remainder bits set ---- */ +static bm_word_t *make_map(uint64_t count) +{ + uint64_t nw = BM_NWORDS(count), b; + bm_word_t *bm = calloc(nw, sizeof(bm_word_t)); + for (b = count; b < nw * BM_WORD_BITS; b++) + bm_set(bm, b); + return bm; +} + +static void test_bitmap_basic(void) +{ + uint64_t count = 200; /* not a multiple of 64 -> exercises remainder */ + bm_word_t *bm = make_map(count); + uint64_t i, bit, n = 0; + char *seen = calloc(count, 1); + + /* allocate the whole pool via rolling cursor; each bit unique and < count */ + uint64_t cursor = 0; + while ((bit = bm_find_free(bm, count, cursor)) != BM_INVALID) { + CHECK(bit < count); + CHECK(!seen[bit]); + seen[bit] = 1; + bm_set(bm, bit); + cursor = bit + 1; + n++; + CHECK(n <= count); + } + CHECK(n == count); /* exactly count handed out */ + for (i = 0; i < count; i++) + CHECK(seen[i]); /* every unit handed out once */ + CHECK(bm_find_free(bm, count, 0) == BM_INVALID); /* exhausted */ + + /* free three, confirm exactly those three come back */ + bm_clear(bm, 5); bm_clear(bm, 130); bm_clear(bm, 199); + memset(seen, 0, count); + for (n = 0; (bit = bm_find_free(bm, count, 0)) != BM_INVALID; n++) { + CHECK(bit == 5 || bit == 130 || bit == 199); + seen[bit] = 1; bm_set(bm, bit); + } + CHECK(n == 3 && seen[5] && seen[130] && seen[199]); + + /* wrap-around: only bit 1 free, search starting past it must still find it */ + memset(bm, 0xff, BM_NWORDS(count) * sizeof(bm_word_t)); + bm_clear(bm, 1); + CHECK(bm_find_free(bm, count, 50) == 1); + CHECK(bm_find_free(bm, count, 0) == 1); + + /* zero-size pool */ + CHECK(bm_find_free(bm, 0, 0) == BM_INVALID); + + free(seen); + free(bm); + printf("ok bitmap basic/wrap/remainder/exhaustion\n"); +} + +/* ---- IPv4 geometry (mirrors ippool.c range_addr_to_bit / bit->addr) ---- */ +static uint64_t v4_addr_to_bit(uint32_t start, uint32_t step, int peer_off, + uint64_t count, uint32_t peer) +{ + uint32_t base, delta; + uint64_t bit; + if (peer < (uint32_t)peer_off) return BM_INVALID; + base = peer - peer_off; + if (base < start) return BM_INVALID; + delta = base - start; + if (delta % step) return BM_INVALID; + bit = delta / step; + if (bit >= count) return BM_INVALID; + return bit; +} + +static void test_v4(void) +{ + /* p2p: 10.0.0.0 - 10.0.1.255 (512 addrs), step 1, peer_off 0 */ + uint32_t start = (10u << 24); + uint32_t end = (10u << 24) | 0x1ff; + uint64_t count = (uint64_t)(end - start) + 1; + uint64_t i; + CHECK(count == 512); + for (i = 0; i < count; i++) { + uint32_t peer = start + (uint32_t)i * 1 + 0; + CHECK(v4_addr_to_bit(start, 1, 0, count, peer) == i); + } + CHECK(v4_addr_to_bit(start, 1, 0, count, start - 1) == BM_INVALID); + CHECK(v4_addr_to_bit(start, 1, 0, count, end + 1) == BM_INVALID); + printf("ok v4 p2p round-trip (512 addrs)\n"); + + /* net30: same range, step 4, gw_off 1, peer_off 2 -> 128 blocks */ + count = ((uint64_t)(end - start) + 1) / 4; + CHECK(count == 128); + for (i = 0; i < count; i++) { + uint32_t base = start + (uint32_t)i * 4; + uint32_t peer = base + 2; /* .2 client */ + CHECK(v4_addr_to_bit(start, 4, 2, count, peer) == i); + /* .1 router and .0/.3 are NOT valid leases */ + CHECK(v4_addr_to_bit(start, 4, 2, count, base + 1) == BM_INVALID); + CHECK(v4_addr_to_bit(start, 4, 2, count, base + 0) == BM_INVALID); + CHECK(v4_addr_to_bit(start, 4, 2, count, base + 3) == BM_INVALID); + } + printf("ok v4 net30 round-trip + alignment (128 blocks)\n"); +} + +/* ---- IPv6 helpers: EXACT copies of the ones in ipv6pool.c ---- */ +static void in6_sub(uint8_t *o, const uint8_t *a, const uint8_t *b) +{ + int i, borrow = 0; + for (i = 15; i >= 0; i--) { + int v = (int)a[i] - b[i] - borrow; + if (v < 0) { v += 256; borrow = 1; } else borrow = 0; + o[i] = v; + } +} +static int in6_shr_u64(const uint8_t *d, int shift, uint64_t *out) +{ + int p; uint64_t v = 0; + for (p = 0; p < 64; p++) { + int sp = shift + p; + if (sp < 128 && (d[15 - (sp >> 3)] & (1 << (sp & 7)))) v |= (uint64_t)1 << p; + } + for (p = shift + 64; p < 128; p++) + if (d[15 - (p >> 3)] & (1 << (p & 7))) return -1; + *out = v; return 0; +} +static void in6_index_to_addr(uint8_t *out, const uint8_t *start, uint64_t i, int shift) +{ + uint8_t add[16] = { 0 }; int p, b, carry = 0; + for (p = 0; p < 64; p++) + if (i & ((uint64_t)1 << p)) { int sp = shift + p; if (sp < 128) add[15 - (sp >> 3)] |= (1 << (sp & 7)); } + memcpy(out, start, 16); + for (b = 15; b >= 0; b--) { int s = out[b] + add[b] + carry; out[b] = s & 0xff; carry = s >> 8; } +} +static int in6_cmp(const uint8_t *a, const uint8_t *b) +{ + int i; for (i = 0; i < 16; i++) { if (a[i] < b[i]) return -1; if (a[i] > b[i]) return 1; } return 0; +} +static uint64_t v6_addr_to_bit(const uint8_t *start, int shift, uint64_t count, const uint8_t *addr) +{ + uint8_t delta[16]; uint64_t i; int p; + if (in6_cmp(addr, start) < 0) return BM_INVALID; + in6_sub(delta, addr, start); + for (p = 0; p < shift; p++) + if (delta[15 - (p >> 3)] & (1 << (p & 7))) return BM_INVALID; + if (in6_shr_u64(delta, shift, &i)) return BM_INVALID; + if (i >= count) return BM_INVALID; + return i; +} + +/* ---- __int128 reference ---- */ +static __uint128_t to_u128(const uint8_t a[16]) { __uint128_t v = 0; int i; for (i = 0; i < 16; i++) v = (v << 8) | a[i]; return v; } +static void from_u128(uint8_t a[16], __uint128_t v) { int i; for (i = 15; i >= 0; i--) { a[i] = v & 0xff; v >>= 8; } } + +static void test_v6_one(const char *label, const uint8_t start[16], int mask, int prefix_len) +{ + int shift = 128 - prefix_len; + __uint128_t s = to_u128(start); + __uint128_t hostmask = (mask == 0) ? ~(__uint128_t)0 : (((__uint128_t)1 << (128 - mask)) - 1); + __uint128_t end = s | hostmask; + uint8_t endb[16]; uint8_t delta[16]; uint64_t span, count, i, step_lo; + __uint128_t step = (__uint128_t)1 << shift; + + from_u128(endb, end); + in6_sub(delta, endb, start); + CHECK(in6_shr_u64(delta, shift, &span) == 0); + count = span + 1; + CHECK(count == (uint64_t)(((end - s) >> shift) + 1)); /* matches reference */ + + /* round-trip boundary + sampled indices */ + uint64_t samples[] = { 0, 1, count / 2, count - 1 }; + for (size_t k = 0; k < sizeof(samples) / sizeof(samples[0]); k++) { + i = samples[k]; + if (i >= count) continue; + uint8_t addr[16]; in6_index_to_addr(addr, start, i, shift); + __uint128_t ref = s + (__uint128_t)i * step; + uint8_t refb[16]; from_u128(refb, ref); + CHECK(memcmp(addr, refb, 16) == 0); /* bit->addr matches ref */ + CHECK(v6_addr_to_bit(start, shift, count, addr) == i); /* addr->bit round-trip */ + /* misaligned address (only when there is room below a prefix) */ + if (shift > 0) { + uint8_t bad[16]; memcpy(bad, addr, 16); bad[15] |= 1; + CHECK(v6_addr_to_bit(start, shift, count, bad) == BM_INVALID); + } + } + /* below start and past end reject */ + if (s > 0) { uint8_t below[16]; from_u128(below, s - 1); CHECK(v6_addr_to_bit(start, shift, count, below) == BM_INVALID); } + { uint8_t past[16]; from_u128(past, s + (__uint128_t)count * step); CHECK(v6_addr_to_bit(start, shift, count, past) == BM_INVALID); } + + (void)step_lo; + printf("ok v6 %s (mask=%d plen=%d shift=%d count=%llu)\n", + label, mask, prefix_len, shift, (unsigned long long)count); +} + +static void test_v6(void) +{ + uint8_t a[16]; + + /* 2001:db8::/48 carved into /64s -> 65536 prefixes (mask<=64) */ + memset(a, 0, 16); a[0] = 0x20; a[1] = 0x01; a[2] = 0x0d; a[3] = 0xb8; + test_v6_one("/48->/64", a, 48, 64); + + /* mask>64: 2001:db8:0:0:8000::/72 -> /80 (mask>64 path) */ + memset(a, 0, 16); a[0] = 0x20; a[1] = 0x01; a[2] = 0x0d; a[3] = 0xb8; a[8] = 0x80; + test_v6_one("/72->/80", a, 72, 80); + + /* prefix_len == 128: single addresses, step 1 */ + memset(a, 0, 16); a[0] = 0xfc; a[15] = 0x00; + test_v6_one("/120->/128", a, 120, 128); + + /* unaligned base within the mask host bits (start not on a /64 boundary) */ + memset(a, 0, 16); a[0] = 0x20; a[1] = 0x01; a[2] = 0x0d; a[3] = 0xb8; a[7] = 0x05; + test_v6_one("/48->/64 unaligned base", a, 48, 64); + + /* big delegation: /32 -> /56 = 2^24 prefixes (the cap boundary) */ + memset(a, 0, 16); a[0] = 0x2a; a[1] = 0x00; + test_v6_one("/32->/56 (cap)", a, 32, 56); +} + +int main(void) +{ + test_bitmap_basic(); + test_v4(); + test_v6(); + if (failures) { + printf("\n%d CHECK(s) FAILED\n", failures); + return 1; + } + printf("\nALL TESTS PASSED\n"); + return 0; +} diff --git a/accel-pppd/extra/chap-secrets.c b/accel-pppd/extra/chap-secrets.c index b486bb11..5fd0102c 100644 --- a/accel-pppd/extra/chap-secrets.c +++ b/accel-pppd/extra/chap-secrets.c @@ -6,9 +6,10 @@ #include <netinet/in.h> #include <arpa/inet.h> -#ifdef CRYPTO_OPENSSL -#include "crypto.h" -#endif +#include <openssl/md4.h> +#include <openssl/sha.h> +#include <openssl/des.h> +#include <openssl/evp.h> #include "pwdb.h" #include "ipdb.h" @@ -29,13 +30,11 @@ static int conf_netmask = 0; static void *pd_key; static struct ipdb_t ipdb; -#ifdef CRYPTO_OPENSSL struct hash_chain { struct list_head entry; const EVP_MD *md; }; -#endif struct cs_pd_t { @@ -46,9 +45,7 @@ struct cs_pd_t char *pool; }; -#ifdef CRYPTO_OPENSSL static LIST_HEAD(hash_chain); -#endif static char *skip_word(char *ptr) { @@ -126,19 +123,16 @@ static struct cs_pd_t *create_pd(struct ap_session *ses, const char *username) int n; struct cs_pd_t *pd; struct in_addr in; -#ifdef CRYPTO_OPENSSL char username_hash[EVP_MAX_MD_SIZE * 2 + 1]; uint8_t hash[EVP_MAX_MD_SIZE]; struct hash_chain *hc; EVP_MD_CTX *md_ctx = NULL; char c; int i; -#endif if (!conf_chap_secrets) return NULL; -#ifdef CRYPTO_OPENSSL if (conf_encrypted && !list_empty(&hash_chain)) { unsigned int size = 0; list_for_each_entry(hc, &hash_chain, entry) { @@ -156,7 +150,6 @@ static struct cs_pd_t *create_pd(struct ap_session *ses, const char *username) username = username_hash; } -#endif f = fopen(conf_chap_secrets, "r"); if (!f) { @@ -192,10 +185,8 @@ out: return NULL; found: -#ifdef CRYPTO_OPENSSL if (conf_encrypted && strlen(ptr[1]) != 32) goto out; -#endif pd = _malloc(sizeof(*pd)); if (!pd) { @@ -205,7 +196,6 @@ found: memset(pd, 0, sizeof(*pd)); pd->pd.key = &pd_key; -#ifdef CRYPTO_OPENSSL if (conf_encrypted) { pd->passwd = _malloc(16); if (!pd->passwd) { @@ -221,7 +211,6 @@ found: ptr[1][i*2 + 2] = c; } } else -#endif { pd->passwd = _strdup(ptr[1]); if (!pd->passwd) { @@ -335,10 +324,8 @@ static char* get_passwd(struct pwdb_t *pwdb, struct ap_session *ses, const char { struct cs_pd_t *pd = find_pd(ses); -#ifdef CRYPTO_OPENSSL if (conf_encrypted) return NULL; -#endif if (!pd) pd = create_pd(ses, username); @@ -349,7 +336,6 @@ static char* get_passwd(struct pwdb_t *pwdb, struct ap_session *ses, const char return _strdup(pd->passwd); } -#ifdef CRYPTO_OPENSSL static void des_encrypt(const uint8_t *input, const uint8_t *key, uint8_t *output) { int i, j, parity; @@ -684,7 +670,6 @@ static int check_passwd(struct pwdb_t *pwdb, struct ap_session *ses, pwdb_callba return r; } -#endif static struct ipdb_t ipdb = { .get_ipv4 = get_ip, @@ -692,12 +677,9 @@ static struct ipdb_t ipdb = { static struct pwdb_t pwdb = { .get_passwd = get_passwd, -#ifdef CRYPTO_OPENSSL .check = check_passwd, -#endif }; -#ifdef CRYPTO_OPENSSL static void clear_hash_chain(void) { struct hash_chain *hc; @@ -731,7 +713,6 @@ static void parse_hash_chain(const char *opt) ptr1 = ptr2 + 1; } } -#endif static void parse_gw_ip_address(const char *opt) { @@ -792,12 +773,10 @@ static void load_config(void) else conf_encrypted = 0; -#ifdef CRYPTO_OPENSSL clear_hash_chain(); opt = conf_get_opt("chap-secrets", "username-hash"); if (opt) parse_hash_chain(opt); -#endif } static void init(void) diff --git a/accel-pppd/extra/ippool.c b/accel-pppd/extra/ippool.c index 3ae48e95..e935bb4c 100644 --- a/accel-pppd/extra/ippool.c +++ b/accel-pppd/extra/ippool.c @@ -3,138 +3,161 @@ #include <stdint.h> #include <unistd.h> #include <string.h> +#include <pthread.h> #include <arpa/inet.h> +#include "triton.h" #include "events.h" #include "log.h" #include "list.h" #include "spinlock.h" #include "backup.h" +#include "ap_session.h" #include "ap_session_backup.h" #include "ipdb.h" +#include "cli.h" #ifdef RADIUS #include "radius.h" #endif +#include "bitpool.h" #include "memdebug.h" -struct ippool_t; - -typedef void (*generate_func)(struct ippool_t *); +/* + * Bitmap IPv4 address pool. + * + * Each pool holds a list of contiguous ranges; each range owns one bitmap + * (1 bit per allocatable block). A lease is a small per-session malloc wrapper + * around the ipv4db_item_t returned to the session, so pool memory is never + * shared/mutated by sessions. The whole pool set is rebuilt and swapped on + * EV_CONFIG_RELOAD, reconciling live sessions against the new ranges. + * + * TODO: a sparse/hierarchical allocator would lift IPPOOL_MAX_BITS; the dense + * bitmap is fine for realistic IPv4 ranges (a /8 sits right at the cap). + */ + +#define IPPOOL_MAX_BITS (1u << 24) /* ~16.7M units, ~2MB bitmap */ + +enum { + ORPHAN_KEEP = 0, /* keep the session, no-op its later put */ + ORPHAN_DISCONNECT, /* terminate sessions whose address left the pools */ +}; -struct ippool_t -{ +/* one contiguous range = one bitmap. step/offsets encode the allocator: + * p2p: step=1, gw_offset=-1 (local addr from gw-ip-address/0), peer_offset=0 + * net30: step=4, gw_offset=1 (.1 router), peer_offset=2 (.2 client) */ +struct ip_range { struct list_head entry; - char *name; - struct list_head gw_list; - struct list_head tunnel_list; - struct list_head items; - uint32_t startip; - uint32_t endip; - struct ippool_t *next; - generate_func generate; - spinlock_t lock; + uint32_t start; /* host order, first block base */ + uint32_t end; /* host order, last address in range */ + uint32_t step; + int gw_offset; + int peer_offset; + uint64_t count; /* number of blocks = bits in bitmap */ + uint64_t cursor; /* round-robin search hint */ + uint64_t used; + bm_word_t *bitmap; }; -struct ippool_item_t -{ - struct list_head entry; - struct ippool_t *pool; - struct ipv4db_item_t it; +struct ip_pool { + struct list_head entry; /* in set->pools; named pools only */ + char *name; /* NULL for the default pool */ + struct ip_pool *next; /* overflow chain */ + struct list_head ranges; + spinlock_t lock; /* guards every range's bitmap/cursor/used */ }; -struct ipaddr_t -{ +struct pool_set { + struct list_head pools; /* named pools */ + struct ip_pool *def_pool; /* unnamed default (not on `pools`) */ + in_addr_t gw_ip_address; /* prevents the configured gateway address from being handed out as a peer address */ + int shuffle; + int orphan_policy; +}; + +struct ip_lease { + struct ip_pool *pool; /* NULL once orphaned by a reload */ + struct ip_range *range; /* Range that supplied this lease's peer address; NULL if orphaned */ + struct ipv4db_item_t it; /* ses->ipv4 = &it */ +}; + +/* collected during reconcile, acted on after locks are dropped */ +struct disc_node { struct list_head entry; - in_addr_t addr; + struct ap_session *ses; }; static struct ipdb_t ipdb; -static in_addr_t conf_gw_ip_address; -static int conf_shuffle; +static pthread_rwlock_t pool_set_rwlock = PTHREAD_RWLOCK_INITIALIZER; +static struct pool_set *cur_set; #ifdef RADIUS static int conf_vendor = 0; static int conf_attr = 88; // Framed-Pool -#endif - -static int cnt; -static LIST_HEAD(pool_list); -static struct ippool_t *def_pool; -struct ippool_t *create_pool(char *name) +static int parse_attr_opt(const char *opt) { - struct ippool_t *p = malloc(sizeof(*p)); + struct rad_dict_attr_t *attr; + struct rad_dict_vendor_t *vendor; - memset(p, 0, sizeof(*p)); - p->name = name; + if (conf_vendor) + vendor = rad_dict_find_vendor_id(conf_vendor); + else + vendor = NULL; - INIT_LIST_HEAD(&p->gw_list); - INIT_LIST_HEAD(&p->tunnel_list); - INIT_LIST_HEAD(&p->items); - spinlock_init(&p->lock); + if (conf_vendor) { + if (vendor) + attr = rad_dict_find_vendor_attr(vendor, opt); + else + attr = NULL; + } else + attr = rad_dict_find_attr(opt); - if (name) - list_add_tail(&p->entry, &pool_list); + if (attr) + return attr->id; - return p; + return atoi(opt); } -struct ippool_t *find_pool(char *name, int create) +static int parse_vendor_opt(const char *opt) { - struct ippool_t *p; - - list_for_each_entry(p, &pool_list, entry) { - if (!strcmp(p->name, name)) - return p; - } + struct rad_dict_vendor_t *vendor; - if (create) - return create_pool(name); + vendor = rad_dict_find_vendor_name(opt); + if (vendor) + return vendor->id; - return NULL; + return atoi(opt); } +#endif -static void parse_gw_ip_address(const char *val) +/* ===== randomness for shuffle ===== */ + +static uint64_t rand_u64(void) { - char addr[17]; - char *ptr; + uint64_t r = 0; - if (!val) - return; + if (read(urandom_fd, &r, sizeof(r)) != sizeof(r)) + r = 0; - ptr = strchr(val, '/'); - if (ptr) { - // safeguard, don't crash on oversized or undersized strings - if (ptr - val > 15 || ptr - val < 7) - return; - memcpy(addr, val, ptr - val); - addr[ptr - val] = 0; - conf_gw_ip_address = inet_addr(addr); - } - else - conf_gw_ip_address = inet_addr(val); + return r; } +/* ===== range arithmetic ===== */ + //parses ranges like x.x.x.x/mask static int parse1(const char *str, uint32_t *begin, uint32_t *end) { int n; unsigned int f1, f2, f3, f4, m; - n = sscanf(str, "%u.%u.%u.%u/%u",&f1, &f2, &f3, &f4, &m); + n = sscanf(str, "%u.%u.%u.%u/%u", &f1, &f2, &f3, &f4, &m); if (n != 5) return -1; - if (f1 > 255) - return -1; - if (f2 > 255) - return -1; - if (f3 > 255) - return -1; - if (f4 > 255) + if (f1 > 255 || f2 > 255 || f3 > 255 || f4 > 255) return -1; if (m == 0 || m > 32) return -1; @@ -153,16 +176,10 @@ static int parse2(const char *str, uint32_t *begin, uint32_t *end) int n; unsigned int f1, f2, f3, f4, f5; - n = sscanf(str, "%u.%u.%u.%u-%u",&f1, &f2, &f3, &f4, &f5); + n = sscanf(str, "%u.%u.%u.%u-%u", &f1, &f2, &f3, &f4, &f5); if (n != 5) return -1; - if (f1 > 255) - return -1; - if (f2 > 255) - return -1; - if (f3 > 255) - return -1; - if (f4 > 255) + if (f1 > 255 || f2 > 255 || f3 > 255 || f4 > 255) return -1; if (f5 < f4 || f5 > 255) return -1; @@ -173,222 +190,514 @@ static int parse2(const char *str, uint32_t *begin, uint32_t *end) return 0; } -static void add_range(struct ippool_t *p, struct list_head *list, const char *name, void (*generate)(struct ippool_t *)) +/* bit index of a leased peer address within a range, or BM_INVALID */ +static uint64_t range_addr_to_bit(const struct ip_range *r, uint32_t peer_host) { - uint32_t i,startip, endip; - struct ipaddr_t *ip; + uint32_t base, delta; + uint64_t bit; + + if (peer_host < (uint32_t)r->peer_offset) + return BM_INVALID; + base = peer_host - r->peer_offset; + if (base < r->start) + return BM_INVALID; + delta = base - r->start; + if (delta % r->step) + return BM_INVALID; + bit = delta / r->step; + if (bit >= r->count) + return BM_INVALID; + + return bit; +} - if (parse1(name, &startip, &endip)) { - if (parse2(name, &startip, &endip)) { - fprintf(stderr, "ippool: cann't parse '%s'\n", name); - _exit(EXIT_FAILURE); - } +/* ===== pool set construction ===== */ + +static struct ip_pool *create_pool(struct pool_set *set, char *name) +{ + struct ip_pool *p = _malloc(sizeof(*p)); + + if (!p) + return NULL; + + memset(p, 0, sizeof(*p)); + p->name = name; + INIT_LIST_HEAD(&p->ranges); + spinlock_init(&p->lock); + + if (name) + list_add_tail(&p->entry, &set->pools); + + return p; +} + +static struct ip_pool *find_pool(struct pool_set *set, const char *name, int create) +{ + struct ip_pool *p; + + list_for_each_entry(p, &set->pools, entry) { + if (p->name && !strcmp(p->name, name)) + return p; } - for (i = startip; i <= endip; i++) { - ip = malloc(sizeof(*ip)); - ip->addr = htonl(i); - list_add_tail(&ip->entry, list); - cnt++; + if (create) { + char *dup = _strdup(name); + if (!dup) + return NULL; + return create_pool(set, dup); } - p->startip = startip; - p->endip = endip; - p->generate = generate; + return NULL; } -static uint8_t get_random() +static int add_range_to_pool(struct ip_pool *p, const char *str, + uint32_t step, int gw_offset, int peer_offset) { - static uint8_t buf[128]; - static int pos = 0; - int r; + uint32_t start, end; + uint64_t count; + struct ip_range *r; - if (pos == 0) - read(urandom_fd, buf, 128); + if (parse1(str, &start, &end)) { + if (parse2(str, &start, &end)) { + log_error("ippool: can't parse range '%s'\n", str); + return -1; + } + } - r = buf[pos++]; + if (end < start) { + log_error("ippool: range '%s' ends before it starts\n", str); + return -1; + } - if (pos == 128) - pos = 0; + count = ((uint64_t)(end - start) + 1) / step; /* floor: net30 tail dropped */ + if (count == 0) { + log_warn("ippool: range '%s' is empty for this allocator\n", str); + return 0; + } + if (count > IPPOOL_MAX_BITS) { + log_error("ippool: range '%s' has %llu units, exceeds cap %u; skipping\n", + str, (unsigned long long)count, IPPOOL_MAX_BITS); + return -1; + } - return r; + r = _malloc(sizeof(*r)); + if (!r) + return -1; + memset(r, 0, sizeof(*r)); + r->start = start; + r->end = end; + r->step = step; + r->gw_offset = gw_offset; + r->peer_offset = peer_offset; + r->count = count; + list_add_tail(&r->entry, &p->ranges); + + return 0; } -static void generate_pool_p2p(struct ippool_t *p) +/* allocate + finalize bitmaps once the whole section (incl. gw-ip-address) is known */ +static int finalize_ranges(struct pool_set *set, struct ip_pool *p) { - struct ippool_item_t *it; - struct ipaddr_t *addr = NULL; - struct ipaddr_t *peer_addr; - struct list_head *pos = NULL, *pos1 = p->tunnel_list.next, *pos2 = p->tunnel_list.prev; - uint8_t r, t = 0; - - while (1) { - if (list_empty(&p->tunnel_list)) - break; - else { - if (conf_shuffle) { - if (pos1 == &p->tunnel_list) - pos1 = pos1->next; - - if (pos2 == &p->tunnel_list) - pos2 = pos2->prev; - - if (t++ < 10) - r = get_random(); - else - r = get_random()%64; - - if (r < 32) - pos = pos1; - else if (r < 64) - pos = pos2; - - pos1 = pos1->next; - pos2 = pos2->prev; - - if (r >= 64) - continue; - - peer_addr = list_entry(pos, typeof(*peer_addr), entry); - if (pos == pos1) - pos1 = pos1->next; - - if (pos == pos2) - pos2 = pos2->prev; - - list_del(&peer_addr->entry); - t = 0; - } else { - peer_addr = list_entry(p->tunnel_list.next, typeof(*peer_addr), entry); - list_del(&peer_addr->entry); + struct ip_range *r; + + list_for_each_entry(r, &p->ranges, entry) { + uint64_t nw = BM_NWORDS(r->count); + uint64_t b; + + r->bitmap = _malloc(nw * sizeof(bm_word_t)); + if (!r->bitmap) + return -1; + memset(r->bitmap, 0, nw * sizeof(bm_word_t)); + + /* remainder bits past count must never be handed out */ + for (b = r->count; b < nw * BM_WORD_BITS; b++) + bm_set(r->bitmap, b); + + /* p2p: reserve the bit colliding with the configured gateway, + * reproducing the old generate_pool_p2p skip */ + if (r->step == 1 && r->peer_offset == 0 && set->gw_ip_address) { + uint32_t gw = ntohl(set->gw_ip_address); + if (gw >= r->start && gw <= r->end) { + uint64_t bit = gw - r->start; + if (bit < r->count && !bm_test(r->bitmap, bit)) { + bm_set(r->bitmap, bit); + r->used++; + } } } + } - if (!conf_gw_ip_address) { - if (list_empty(&p->gw_list)) - break; - else { - addr = list_entry(p->gw_list.next, typeof(*addr), entry); - list_del(&addr->entry); - } - } else if (conf_gw_ip_address == peer_addr->addr) - continue; + return 0; +} - it = malloc(sizeof(*it)); - if (!it) { - fprintf(stderr, "ippool: out of memory\n"); - break; +static void parse_gw_ip_address(const char *val, in_addr_t *out) +{ + char addr[17]; + char *ptr; + + if (!val) + return; + + ptr = strchr(val, '/'); + if (ptr) { + if (ptr - val > 15 || ptr - val < 7) + return; + memcpy(addr, val, ptr - val); + addr[ptr - val] = 0; + *out = inet_addr(addr); + } else + *out = inet_addr(val); +} + +/* parse ,name= / ,allocator= / ,next= from a raw option line */ +static int parse_line_opts(struct pool_set *set, const char *opt, struct ip_pool **pool, + uint32_t *step, int *gw_offset, int *peer_offset) +{ + char *name, *ptr; + + name = strstr(opt, ",name="); + if (name) { + name += sizeof(",name=") - 1; + ptr = strchrnul(name, ','); + name = _strndup(name, ptr - name); + if (!name) + return -1; + *pool = find_pool(set, name, 1); + _free(name); + } else if ((name = strchr(opt, ',')) && !strchr(name + 1, '=')) { + name = _strndup(name + 1, strchrnul(name + 1, ',') - (name + 1)); + if (!name) + return -1; + *pool = find_pool(set, name, 1); + _free(name); + } else + *pool = set->def_pool; + + if (!*pool) + return -1; + + /* defaults: p2p */ + *step = 1; + *gw_offset = -1; + *peer_offset = 0; + + name = strstr(opt, ",allocator="); + if (name) { + name += sizeof(",allocator=") - 1; + ptr = strchrnul(name, ','); + if (!strncmp(name, "p2p", ptr - name) && (size_t)(ptr - name) == 3) { + *step = 1; *gw_offset = -1; *peer_offset = 0; + } else if (!strncmp(name, "net30", ptr - name) && (size_t)(ptr - name) == 5) { + *step = 4; *gw_offset = 1; *peer_offset = 2; + } else { + log_error("ippool: '%s': unknown allocator\n", opt); + return -1; } + } - memset(it, 0, sizeof(*it)); - it->pool = p; - it->it.owner = &ipdb; - if (conf_gw_ip_address) - it->it.addr = conf_gw_ip_address; - else - it->it.addr = addr->addr; + name = strstr(opt, ",next="); + if (name) { + struct ip_pool *next; + name += sizeof(",next=") - 1; + ptr = strchrnul(name, ','); + name = _strndup(name, ptr - name); + if (!name) + return -1; + next = find_pool(set, name, 1); + _free(name); + if (next) + (*pool)->next = next; + } - it->it.peer_addr = peer_addr->addr; + return 0; +} - list_add_tail(&it->entry, &p->items); +static void free_pool(struct ip_pool *p) +{ + struct ip_range *r; + + while (!list_empty(&p->ranges)) { + r = list_first_entry(&p->ranges, typeof(*r), entry); + list_del(&r->entry); + if (r->bitmap) + _free(r->bitmap); + _free(r); } + if (p->name) + _free(p->name); + _free(p); } -static void generate_pool_net30(struct ippool_t *p) +static void free_pool_set(struct pool_set *set) { - struct ippool_item_t *it; - struct ipaddr_t *addr[4]; - int i; + struct ip_pool *p; - while (1) { - memset(addr, 0, sizeof(addr)); + if (!set) + return; - for (i = 0; i < 4; i++) { - if (list_empty(&p->tunnel_list)) - break; + while (!list_empty(&set->pools)) { + p = list_first_entry(&set->pools, typeof(*p), entry); + list_del(&p->entry); + free_pool(p); + } + if (set->def_pool) + free_pool(set->def_pool); + _free(set); +} - addr[i] = list_entry(p->tunnel_list.next, typeof(*addr[i]), entry); - list_del(&addr[i]->entry); +static struct pool_set *build_pool_set(void) +{ + struct conf_sect_t *s = conf_get_section("ip-pool"); + struct conf_option_t *opt; + struct pool_set *set; + struct ip_pool *p; + + set = _malloc(sizeof(*set)); + if (!set) + return NULL; + memset(set, 0, sizeof(*set)); + INIT_LIST_HEAD(&set->pools); + set->orphan_policy = ORPHAN_KEEP; + +#ifdef RADIUS + /* statics persist across reloads; reset to defaults so a removed + * vendor/attr line doesn't leave stale values behind */ + conf_vendor = 0; + conf_attr = 88; // Framed-Pool +#endif + + if (!s) + return set; /* no section: an empty (inert) set */ + + set->def_pool = create_pool(set, NULL); + if (!set->def_pool) + goto err; + + list_for_each_entry(opt, &s->items, entry) { + const char *range_str; + struct ip_pool *pool; + uint32_t step; + int gw_offset, peer_offset; + +#ifdef RADIUS + if (triton_module_loaded("radius")) { + if (!strcmp(opt->name, "vendor")) { + if (opt->val) + conf_vendor = parse_vendor_opt(opt->val); + continue; + } else if (!strcmp(opt->name, "attr")) { + if (opt->val) + conf_attr = parse_attr_opt(opt->val); + continue; + } + } +#endif + if (!strcmp(opt->name, "gw-ip-address")) { + parse_gw_ip_address(opt->val, &set->gw_ip_address); + continue; + } + if (!strcmp(opt->name, "shuffle")) { + set->shuffle = opt->val ? atoi(opt->val) : 0; + continue; + } + if (!strcmp(opt->name, "reload-orphan")) { + if (opt->val && !strcmp(opt->val, "disconnect")) + set->orphan_policy = ORPHAN_DISCONNECT; + else + set->orphan_policy = ORPHAN_KEEP; + continue; + } + if (!strcmp(opt->name, "gw")) { + /* deprecated/no-op: the per-block local address has long been + * overwritten at get time by gw-ip-address/0. Accept and ignore. */ + log_warn("ippool: 'gw=' is deprecated and ignored\n"); + continue; } - if (!addr[2]) - break; + if (!strcmp(opt->name, "tunnel")) + range_str = opt->val; + else if (!opt->val || strchr(opt->name, ',')) + range_str = opt->name; + else + continue; /* unrecognized option */ + if (!range_str) + continue; - it = malloc(sizeof(*it)); - if (!it) { - log_emerg("ippool: out of memory\n"); - break; + if (parse_line_opts(set, opt->raw, &pool, &step, &gw_offset, &peer_offset)) { + log_error("ippool: failed to parse '%s'\n", opt->raw); + continue; } - memset(it, 0, sizeof(*it)); - it->pool = p; - it->it.owner = &ipdb; - it->it.addr = addr[1]->addr; - it->it.peer_addr = addr[2]->addr; + add_range_to_pool(pool, range_str, step, gw_offset, peer_offset); + } + + if (finalize_ranges(set, set->def_pool)) + goto err; + list_for_each_entry(p, &set->pools, entry) { + if (finalize_ranges(set, p)) + goto err; + if (list_empty(&p->ranges)) + log_warn("ippool: pool '%s' is empty or not defined\n", p->name); + } + + return set; + +err: + free_pool_set(set); + return NULL; +} - list_add_tail(&it->entry, &p->items); +/* ===== address lookup across a set ===== */ - for (i = 0; i < 4; i++) { - if (addr[i]) - free(addr[i]); +static int pool_contains(struct ip_pool *p, uint32_t peer_host, + struct ip_range **out_r, uint64_t *out_bit) +{ + struct ip_range *r; + + list_for_each_entry(r, &p->ranges, entry) { + uint64_t bit = range_addr_to_bit(r, peer_host); + if (bit != BM_INVALID) { + *out_r = r; + *out_bit = bit; + return 1; } } + return 0; +} - for (i = 0; i < 4; i++) { - if (addr[i]) - free(addr[i]); +/* find the pool+range+bit owning `peer_host`, preferring `pref_name` on overlap */ +static int find_target(struct pool_set *set, uint32_t peer_host, const char *pref_name, + struct ip_pool **op, struct ip_range **orr, uint64_t *obit) +{ + struct ip_pool *p; + + if (!set) + return 0; + + if (pref_name) { + p = find_pool(set, pref_name, 0); + if (p && pool_contains(p, peer_host, orr, obit)) { + *op = p; + return 1; + } + } + + if (set->def_pool && pool_contains(set->def_pool, peer_host, orr, obit)) { + *op = set->def_pool; + return 1; + } + list_for_each_entry(p, &set->pools, entry) { + if (pool_contains(p, peer_host, orr, obit)) { + *op = p; + return 1; + } } + + return 0; } +/* ===== ipdb get/put ===== */ static struct ipv4db_item_t *get_ip(struct ap_session *ses) { - struct ippool_item_t *it; - struct ippool_t *pool, *start; + struct pool_set *set; + struct ip_pool *pool, *start, *found_p = NULL; + struct ip_range *r, *found_r = NULL; + struct ip_lease *lease; + uint64_t bit = BM_INVALID; + uint64_t rnd; + uint32_t base; + + pthread_rwlock_rdlock(&pool_set_rwlock); + set = cur_set; + if (!set) { + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } if (ses->ipv4_pool_name) - pool = find_pool(ses->ipv4_pool_name, 0); + pool = find_pool(set, ses->ipv4_pool_name, 0); else - pool = def_pool; + pool = set->def_pool; - if (!pool) + if (!pool) { + pthread_rwlock_unlock(&pool_set_rwlock); return NULL; + } + + /* draw randomness once, outside the lock: read(urandom_fd) is a + * blocking syscall and must not run while holding pool->lock */ + rnd = set->shuffle ? rand_u64() : 0; start = pool; do { spin_lock(&pool->lock); - if (!list_empty(&pool->items)) { - it = list_entry(pool->items.next, typeof(*it), entry); - list_del(&it->entry); - } else - it = NULL; + list_for_each_entry(r, &pool->ranges, entry) { + uint64_t from = set->shuffle ? (r->count ? rnd % r->count : 0) : r->cursor; + bit = bm_find_free(r->bitmap, r->count, from); + if (bit != BM_INVALID) { + bm_set(r->bitmap, bit); + r->used++; + r->cursor = bit + 1; + found_r = r; + found_p = pool; + break; + } + } spin_unlock(&pool->lock); + if (found_r) + break; + pool = pool->next; + } while (pool && pool != start); - if (it) { - if (ses->ctrl->ppp) - it->it.addr = conf_gw_ip_address; - else - it->it.addr = 0; + if (!found_r) { + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } - it->it.mask = 0; + lease = _malloc(sizeof(*lease)); + if (!lease) { + spin_lock(&found_p->lock); + bm_clear(found_r->bitmap, bit); + found_r->used--; + spin_unlock(&found_p->lock); + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } - return &it->it; - } + memset(lease, 0, sizeof(*lease)); + lease->pool = found_p; + lease->range = found_r; + lease->it.owner = &ipdb; + base = found_r->start + (uint32_t)bit * found_r->step; + lease->it.peer_addr = htonl(base + found_r->peer_offset); + lease->it.addr = ses->ctrl->ppp ? set->gw_ip_address : 0; + lease->it.mask = 0; - pool = pool->next; - } while (pool && pool != start); + pthread_rwlock_unlock(&pool_set_rwlock); - return NULL; + return &lease->it; } static void put_ip(struct ap_session *ses, struct ipv4db_item_t *it) { - struct ippool_item_t *pit = container_of(it, typeof(*pit), it); + struct ip_lease *lease = container_of(it, typeof(*lease), it); + + pthread_rwlock_rdlock(&pool_set_rwlock); + if (lease->pool && lease->range) { + uint64_t bit = range_addr_to_bit(lease->range, ntohl(it->peer_addr)); + spin_lock(&lease->pool->lock); + if (bit != BM_INVALID && bm_test(lease->range->bitmap, bit)) { + bm_clear(lease->range->bitmap, bit); + lease->range->used--; + } + spin_unlock(&lease->pool->lock); + } + /* else: orphaned by a reload - nothing to release, just free the wrapper */ + pthread_rwlock_unlock(&pool_set_rwlock); - spin_lock(&pit->pool->lock); - list_add_tail(&pit->entry, &pit->pool->items); - spin_unlock(&pit->pool->lock); + _free(lease); } static struct ipdb_t ipdb = { @@ -417,9 +726,10 @@ static int session_save(struct ap_session *ses, struct backup_mod *m) static int session_restore(struct ap_session *ses, struct backup_mod *m) { struct backup_tag *tag; - in_addr_t addr = 0, peer_addr; - struct ippool_t *p; - struct ippool_item_t *it, *it0 = NULL; + in_addr_t addr = 0, peer_addr = 0; + struct ip_pool *np; + struct ip_range *nr; + uint64_t bit; m = backup_find_mod(m->data, MODID_COMMON); @@ -434,40 +744,35 @@ static int session_restore(struct ap_session *ses, struct backup_mod *m) } } - spin_lock(&def_pool->lock); - list_for_each_entry(it, &def_pool->items, entry) { - if (peer_addr == it->it.peer_addr && addr == it->it.addr) { - list_del(&it->entry); - it0 = it; - break; - } - } - spin_unlock(&def_pool->lock); - - if (!it0) { - list_for_each_entry(p, &pool_list, entry) { - spin_lock(&p->lock); - list_for_each_entry(it, &p->items, entry) { - if (peer_addr == it->it.peer_addr && addr == it->it.addr) { - list_del(&it->entry); - it0 = it; - break; - } + pthread_rwlock_rdlock(&pool_set_rwlock); + if (find_target(cur_set, ntohl(peer_addr), NULL, &np, &nr, &bit)) { + struct ip_lease *lease = _malloc(sizeof(*lease)); + if (lease) { + memset(lease, 0, sizeof(*lease)); + lease->pool = np; + lease->range = nr; + lease->it.owner = &ipdb; + lease->it.addr = addr; + lease->it.peer_addr = peer_addr; + spin_lock(&np->lock); + if (!bm_test(nr->bitmap, bit)) { + bm_set(nr->bitmap, bit); + nr->used++; } - spin_unlock(&p->lock); - if (it0) - break; + spin_unlock(&np->lock); + ses->ipv4 = &lease->it; } } + pthread_rwlock_unlock(&pool_set_rwlock); - if (it0) - ses->ipv4 = &it0->it; - else { + if (!ses->ipv4) { ses->ipv4 = _malloc(sizeof(*ses->ipv4)); - memset(ses->ipv4, 0, sizeof(*ses->ipv4)); - ses->ipv4->addr = addr; - ses->ipv4->peer_addr = peer_addr; - ses->ipv4->owner = &ipdb_b; + if (ses->ipv4) { + memset(ses->ipv4, 0, sizeof(*ses->ipv4)); + ses->ipv4->addr = addr; + ses->ipv4->peer_addr = peer_addr; + ses->ipv4->owner = &ipdb_b; + } } return 0; @@ -480,6 +785,101 @@ static struct backup_module backup_mod = { }; #endif +/* ===== reconcile on reload ===== */ + +static void reconcile_v4(struct pool_set *new_set, struct ap_session *ses, + int policy, struct list_head *disc) +{ + struct ipv4db_item_t *it = ses->ipv4; + uint32_t peer_host; + struct ip_pool *np; + struct ip_range *nr; + uint64_t bit; + + if (!it || !it->owner) + return; + + peer_host = ntohl(it->peer_addr); + + if (it->owner == &ipdb) { + struct ip_lease *lease = container_of(it, typeof(*lease), it); + if (find_target(new_set, peer_host, ses->ipv4_pool_name, &np, &nr, &bit)) { + spin_lock(&np->lock); + if (!bm_test(nr->bitmap, bit)) { + bm_set(nr->bitmap, bit); + nr->used++; + } + spin_unlock(&np->lock); + lease->pool = np; + lease->range = nr; + } else { + lease->pool = NULL; + lease->range = NULL; + if (policy == ORPHAN_DISCONNECT) { + struct disc_node *d = _malloc(sizeof(*d)); + if (d) { + d->ses = ses; + list_add_tail(&d->entry, disc); + } + } + } + } else { + /* foreign owner (radius/chap-secrets/static): reserve the bit so we + * never hand out a live address. We do not own or free it. */ + if (find_target(new_set, peer_host, NULL, &np, &nr, &bit)) { + spin_lock(&np->lock); + if (!bm_test(nr->bitmap, bit)) { + bm_set(nr->bitmap, bit); + nr->used++; + } + spin_unlock(&np->lock); + } + } +} + +static void terminate_orphan(void *arg) +{ + struct ap_session *ses = arg; + ap_session_terminate(ses, TERM_NAS_REBOOT, 0); +} + +static void load_config(void *data) +{ + struct pool_set *new_set, *old_set; + struct ap_session *ses; + struct disc_node *d; + LIST_HEAD(disc_list); + int policy; + + new_set = build_pool_set(); + if (!new_set) { + log_error("ippool: reload failed, keeping current pools\n"); + return; + } + policy = new_set->orphan_policy; + + pthread_rwlock_wrlock(&pool_set_rwlock); + pthread_rwlock_rdlock(&ses_lock); + + list_for_each_entry(ses, &ses_list, entry) + reconcile_v4(new_set, ses, policy, &disc_list); + + old_set = cur_set; + cur_set = new_set; + + pthread_rwlock_unlock(&ses_lock); + pthread_rwlock_unlock(&pool_set_rwlock); + + free_pool_set(old_set); + + while (!list_empty(&disc_list)) { + d = list_first_entry(&disc_list, typeof(*d), entry); + list_del(&d->entry); + triton_context_call(d->ses->ctrl->ctx, terminate_orphan, d->ses); + _free(d); + } +} + #ifdef RADIUS static int parse_attr(struct ap_session *ses, struct rad_attr_t *attr) { @@ -516,97 +916,70 @@ static void ev_radius_access_accept(struct ev_radius_t *ev) parse_attr(ev->ses, attr); } } +#endif -static int parse_attr_opt(const char *opt) -{ - struct rad_dict_attr_t *attr; - struct rad_dict_vendor_t *vendor; +/* ===== cli ===== */ - if (conf_vendor) - vendor = rad_dict_find_vendor_id(conf_vendor); - else - vendor = NULL; +static int show_ippool_exec(const char *cmd, char * const *fields, int fields_cnt, void *client) +{ + struct ip_pool *pool; + struct ip_range *r; + uint64_t total, used; - if (conf_vendor) { - if (vendor) - attr = rad_dict_find_vendor_attr(vendor, opt); - else - attr = NULL; - }else - attr = rad_dict_find_attr(opt); + cli_send(client, "IP Pool Usage Report\r\n"); + cli_send(client, "====================\r\n"); - if (attr) - return attr->id; + pthread_rwlock_rdlock(&pool_set_rwlock); + if (!cur_set) { + pthread_rwlock_unlock(&pool_set_rwlock); + return CLI_CMD_OK; + } - return atoi(opt); -} + if (cur_set->def_pool) { + pool = cur_set->def_pool; + total = used = 0; + spin_lock(&pool->lock); + list_for_each_entry(r, &pool->ranges, entry) { + total += r->count; + used += r->used; + } + spin_unlock(&pool->lock); + if (total > 0) + cli_sendv(client, "<default>\r\n total: %llu\r\n used: %llu\r\n available: %llu\r\n usage: %llu%%\r\n", + (unsigned long long)total, (unsigned long long)used, + (unsigned long long)(total - used), + (unsigned long long)(used * 100 / total)); + } -static int parse_vendor_opt(const char *opt) -{ - struct rad_dict_vendor_t *vendor; + list_for_each_entry(pool, &cur_set->pools, entry) { + if (!pool->name) + continue; + total = used = 0; + spin_lock(&pool->lock); + list_for_each_entry(r, &pool->ranges, entry) { + total += r->count; + used += r->used; + } + spin_unlock(&pool->lock); + if (total > 0) + cli_sendv(client, "%s\r\n total: %llu\r\n used: %llu\r\n available: %llu\r\n usage: %llu%%\r\n", + pool->name, (unsigned long long)total, (unsigned long long)used, + (unsigned long long)(total - used), + (unsigned long long)(used * 100 / total)); + } - vendor = rad_dict_find_vendor_name(opt); - if (vendor) - return vendor->id; + pthread_rwlock_unlock(&pool_set_rwlock); - return atoi(opt); + return CLI_CMD_OK; } -#endif -static int parse_options(const char *opt, struct ippool_t **pool, generate_func *generate, struct ippool_t **next) +static void show_ippool_help(char * const *fields, int fields_cnt, void *client) { - char *name, *ptr; - - name = strstr(opt, ",name="); - if (name) { - name += sizeof(",name=") - 1; - ptr = strchrnul(name, ','); - name = _strndup(name, ptr - name); - if (!name) - return -1; - *pool = find_pool(name, 1); - } else if ((name = strchr(opt, ',')) && !strchr(name + 1, '=')) { - name = _strdup(name + 1); - if (!name) - return -1; - *pool = find_pool(name, 1); - } else - *pool = def_pool; - - name = strstr(opt, ",allocator="); - if (name) { - name += sizeof(",allocator=") - 1; - ptr = strchrnul(name, ','); - name = strncpy(alloca(ptr - name + 1), name, ptr - name + 1); - if (strcmp(name, "p2p") == 0) - *generate = generate_pool_p2p; - else if (strcmp(name, "net30") == 0) - *generate = generate_pool_net30; - else { - log_error("ipool: '%s': unknown allocator\n", opt); - return -1; - } - } else - *generate = generate_pool_p2p; - - name = strstr(opt, ",next="); - if (name) { - name += sizeof(",next=") - 1; - ptr = strchrnul(name, ','); - name = strncpy(alloca(ptr - name + 1), name, ptr - name + 1); - *next = find_pool(name, 0); - if (!*next) { - name = _strdup(name); - if (!name) - return -1; - *next = find_pool(name, 1); - } - } else - *next = NULL; - - return 0; + cli_send(client, "show ippool - shows IP pool statistics\r\n"); } +/* ===== init ===== */ + static void ippool_init1(void) { ipdb_register(&ipdb); @@ -614,59 +987,11 @@ static void ippool_init1(void) static void ippool_init2(void) { - struct conf_sect_t *s = conf_get_section("ip-pool"); - struct conf_option_t *opt; - struct ippool_t *pool, *next; - generate_func generate; + load_config(NULL); - if (!s) - return; - - def_pool = create_pool(NULL); - - list_for_each_entry(opt, &s->items, entry) { -#ifdef RADIUS - if (triton_module_loaded("radius")) { - if (!strcmp(opt->name, "vendor")) { - conf_vendor = parse_vendor_opt(opt->val); - continue; - } else if (!strcmp(opt->name, "attr")) { - conf_attr = parse_attr_opt(opt->val); - continue; - } - } -#endif - if (!strcmp(opt->name, "gw-ip-address")) - parse_gw_ip_address(opt->val); - else if (!strcmp(opt->name, "shuffle")) - conf_shuffle = atoi(opt->val); - else { - if (parse_options(opt->raw, &pool, &generate, &next)) { - log_error("ippool: failed to parse '%s'\n", opt->raw); - continue; - } - - if (!strcmp(opt->name, "gw")) - add_range(pool, &pool->gw_list, opt->val, generate); - else if (!strcmp(opt->name, "tunnel")) - add_range(pool, &pool->tunnel_list, opt->val, generate); - else if (!opt->val || strchr(opt->name, ',')) - add_range(pool, &pool->tunnel_list, opt->name, generate); - - if (next) - pool->next = next; - } - } - - if (def_pool->generate) - def_pool->generate(def_pool); - - list_for_each_entry(pool, &pool_list, entry) { - if (pool->generate) - pool->generate(pool); - else - log_warn("ippool: pool '%s' is empty or not defined\n", pool->name); - } + if (triton_event_register_handler(EV_CONFIG_RELOAD, load_config) < 0) + log_error("ippool: registration of CONFIG_RELOAD event failed," + " pools will not reload\n"); #ifdef USE_BACKUP backup_register_module(&backup_mod); @@ -676,6 +1001,8 @@ static void ippool_init2(void) if (triton_module_loaded("radius")) triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept); #endif + + cli_register_simple_cmd2(show_ippool_exec, show_ippool_help, 2, "show", "ippool"); } DEFINE_INIT(51, ippool_init1); diff --git a/accel-pppd/extra/ipv6pool.c b/accel-pppd/extra/ipv6pool.c index c5cabef5..9a763445 100644 --- a/accel-pppd/extra/ipv6pool.c +++ b/accel-pppd/extra/ipv6pool.c @@ -3,76 +3,112 @@ #include <stdint.h> #include <unistd.h> #include <string.h> -#include <unistd.h> #include <fcntl.h> +#include <pthread.h> #include <arpa/inet.h> +#include <netinet/in.h> #include <endian.h> +#include "triton.h" #include "events.h" #include "ipdb.h" #include "list.h" #include "log.h" #include "spinlock.h" +#include "ap_session.h" #ifdef RADIUS #include "radius.h" #endif +#include "bitpool.h" #include "memdebug.h" -enum ippool_type -{ - IPPOOL_ADDRESS, - IPPOOL_PREFIX +/* + * Bitmap IPv6 address (IA_NA) and delegated-prefix (IA_PD) pools. + * + * Same model as the IPv4 pool: each pool holds a list of contiguous ranges, + * each range owns one bitmap indexing per-lease prefixes (bit i -> start + + * i*2^(128-prefix_len)). A lease is a per-session malloc wrapper that embeds + * the single ipv6db_addr_t node linked into the item's addr/prefix list. The + * whole set is rebuilt and swapped on EV_CONFIG_RELOAD with a reconcile pass. + * + * TODO: a sparse/hierarchical allocator would lift IPPOOL_MAX_BITS; the dense + * bitmap requires (prefix_len - mask) <= 24, i.e. <= ~16.7M prefixes per range. + */ + +#define IPPOOL_MAX_BITS (1u << 24) +#define IPPOOL_MAX_SHIFT 24 /* prefix_len - mask cap (2^24 entries) */ + +enum ippool_type { + IPPOOL_ADDRESS, + IPPOOL_PREFIX, }; -struct ippool_t -{ +enum { + ORPHAN_KEEP = 0, + ORPHAN_DISCONNECT, +}; + +struct ip6_range { struct list_head entry; - char *name; - struct list_head gw_list; - struct list_head items; - struct ippool_t *next; - spinlock_t lock; + struct in6_addr start; + int prefix_len; + int shift; /* 128 - prefix_len */ + uint64_t count; /* number of prefixes = bits */ + uint64_t cursor; + uint64_t used; + bm_word_t *bitmap; }; -struct ippool_item_t -{ +struct ip6_pool { struct list_head entry; - struct ippool_t *pool; - struct ipv6db_item_t it; + char *name; /* NULL for default pool */ + struct ip6_pool *next; + struct list_head ranges; + spinlock_t lock; }; -struct dppool_item_t -{ +struct pool_set { + struct list_head ippools; /* named NA pools */ + struct list_head dppools; /* named PD pools */ + struct ip6_pool *def_ippool; + struct ip6_pool *def_dppool; + struct in6_addr gw_addr; + int orphan_policy; +}; + +struct ip6_lease { + struct ip6_pool *pool; + struct ip6_range *range; + struct ipv6db_item_t it; /* ses->ipv6 = &it */ + struct ipv6db_addr_t node; /* linked into it.addr_list */ +}; + +struct dp_lease { + struct ip6_pool *pool; + struct ip6_range *range; + struct ipv6db_prefix_t it; /* ses->ipv6_dp = &it */ + struct ipv6db_addr_t node; /* linked into it.prefix_list */ +}; + +struct disc_node { struct list_head entry; - struct ippool_t *pool; - struct ipv6db_prefix_t it; + struct ap_session *ses; }; +static struct ipdb_t ipdb; + +static pthread_rwlock_t pool_set_rwlock = PTHREAD_RWLOCK_INITIALIZER; +static struct pool_set *cur_set; + #ifdef RADIUS static int conf_vendor = 0; static int conf_dppool_attr = 171; // Delegated-IPv6-Prefix-Pool static int conf_ippool_attr = 172; // Stateful-IPv6-Address-Pool #endif -static LIST_HEAD(ippool_list); -static LIST_HEAD(dppool_list); -static struct ipdb_t ipdb; -static struct in6_addr conf_gw_addr; -static struct ippool_t *def_ippool; -static struct ippool_t *def_dppool; - -static void in6_addr_add(struct in6_addr *res, const struct in6_addr *arg) -{ - uint16_t n = 0; - int i; - - for (i = 15; i >= 0; i--) { - n = (uint16_t)res->s6_addr[i] + arg->s6_addr[i] + (n >> 8); - res->s6_addr[i] = n & 0xff; - } -} +/* ===== 128-bit helpers (big-endian s6_addr[16]) ===== */ static int in6_addr_cmp(const struct in6_addr *n1, const struct in6_addr *n2) { @@ -88,154 +124,205 @@ static int in6_addr_cmp(const struct in6_addr *n1, const struct in6_addr *n2) return 0; } -static struct ippool_t *create_pool(enum ippool_type type, char *name) +/* o = a - b (assumes a >= b) */ +static void in6_sub(uint8_t *o, const uint8_t *a, const uint8_t *b) { - struct ippool_t *pool = malloc(sizeof(*pool)); - struct list_head *pool_list = (type == IPPOOL_PREFIX) ? &dppool_list : &ippool_list; + int i, borrow = 0; - memset(pool, 0, sizeof(*pool)); - pool->name = name; + for (i = 15; i >= 0; i--) { + int v = (int)a[i] - b[i] - borrow; + if (v < 0) { + v += 256; + borrow = 1; + } else + borrow = 0; + o[i] = v; + } +} - INIT_LIST_HEAD(&pool->items); - spinlock_init(&pool->lock); +/* floor(delta >> shift) into *out; returns -1 if it doesn't fit in uint64 */ +static int in6_shr_u64(const uint8_t *d, int shift, uint64_t *out) +{ + int p; + uint64_t v = 0; - if (name) - list_add_tail(&pool->entry, pool_list); + for (p = 0; p < 64; p++) { + int sp = shift + p; + if (sp < 128 && (d[15 - (sp >> 3)] & (1 << (sp & 7)))) + v |= (uint64_t)1 << p; + } + for (p = shift + 64; p < 128; p++) { + if (d[15 - (p >> 3)] & (1 << (p & 7))) + return -1; + } - return pool; + *out = v; + return 0; } -static struct ippool_t *find_pool(enum ippool_type type, char *name, int create) +/* out = start + (i << shift) */ +static void in6_index_to_addr(struct in6_addr *out, const struct in6_addr *start, + uint64_t i, int shift) { - struct ippool_t *pool; - struct list_head *pool_list = (type == IPPOOL_PREFIX) ? &dppool_list : &ippool_list; - - list_for_each_entry(pool, pool_list, entry) { - if (!strcmp(pool->name, name)) - return pool; + uint8_t add[16] = { 0 }; + int p, b, carry = 0; + + for (p = 0; p < 64; p++) { + if (i & ((uint64_t)1 << p)) { + int sp = shift + p; + if (sp < 128) + add[15 - (sp >> 3)] |= (1 << (sp & 7)); + } } - if (create) - return create_pool(type, name); - - return NULL; + memcpy(out, start, 16); + for (b = 15; b >= 0; b--) { + int s = out->s6_addr[b] + add[b] + carry; + out->s6_addr[b] = s & 0xff; + carry = s >> 8; + } } -static void generate_ippool(struct ippool_t *pool, struct in6_addr *addr, int mask, int prefix_len) +/* bit index of a leased prefix within a range, or BM_INVALID */ +static uint64_t range_addr_to_bit(const struct ip6_range *r, const struct in6_addr *addr) { - struct ippool_item_t *it; - struct ipv6db_addr_t *a; - struct in6_addr ip, end, step; + uint8_t delta[16]; + uint64_t i; + int p; - memcpy(&ip, addr, sizeof(ip)); + if (in6_addr_cmp(addr, &r->start) < 0) + return BM_INVALID; - memcpy(&end, addr, sizeof(end)); - if (mask > 64) - *(uint64_t *)(end.s6_addr + 8) = htobe64(be64toh(*(uint64_t *)(end.s6_addr + 8)) | ((1llu << (128 - mask)) - 1)); - else { - memset(end.s6_addr + 8, 0xff, 8); - *(uint64_t *)end.s6_addr = htobe64(be64toh(*(uint64_t *)end.s6_addr) | ((1llu << (64 - mask)) - 1)); + in6_sub(delta, addr->s6_addr, r->start.s6_addr); + + /* must sit on a prefix boundary: low `shift` bits zero */ + for (p = 0; p < r->shift; p++) { + if (delta[15 - (p >> 3)] & (1 << (p & 7))) + return BM_INVALID; } - memset(&step, 0, sizeof(step)); - if (prefix_len > 64) - *(uint64_t *)(step.s6_addr + 8) = htobe64(1llu << (128 - prefix_len)); - else - *(uint64_t *)step.s6_addr = htobe64(1llu << (64 - prefix_len)); + if (in6_shr_u64(delta, r->shift, &i)) + return BM_INVALID; + if (i >= r->count) + return BM_INVALID; - while (in6_addr_cmp(&ip, &end) <= 0) { - it = malloc(sizeof(*it)); - memset(it, 0, sizeof(*it)); - it->pool = pool; - it->it.owner = &ipdb; - INIT_LIST_HEAD(&it->it.addr_list); - a = malloc(sizeof(*a)); - memset(a, 0, sizeof(*a)); - memcpy(&a->addr, &ip, sizeof(ip)); - a->prefix_len = prefix_len; - list_add_tail(&a->entry, &it->it.addr_list); - list_add_tail(&it->entry, &pool->items); - in6_addr_add(&ip, &step); - } + return i; } -static void generate_dppool(struct ippool_t *pool, struct in6_addr *addr, int mask, int prefix_len) +/* ===== pool set construction ===== */ + +static struct ip6_pool *create_pool(struct list_head *pool_list, char *name) { - struct dppool_item_t *it; - struct in6_addr ip, end, step; - struct ipv6db_addr_t *a; + struct ip6_pool *p = _malloc(sizeof(*p)); - memcpy(&ip, addr, sizeof(ip)); + if (!p) + return NULL; - memcpy(&end, addr, sizeof(end)); - if (mask > 64) - *(uint64_t *)(end.s6_addr + 8) = htobe64(be64toh(*(uint64_t *)(end.s6_addr + 8)) | ((1llu << (128 - mask)) - 1)); - else { - memset(end.s6_addr + 8, 0xff, 8); - *(uint64_t *)end.s6_addr = htobe64(be64toh(*(uint64_t *)end.s6_addr) | ((1llu << (64 - mask)) - 1)); - } + memset(p, 0, sizeof(*p)); + p->name = name; + INIT_LIST_HEAD(&p->ranges); + spinlock_init(&p->lock); - memset(&step, 0, sizeof(step)); - if (prefix_len > 64) - *(uint64_t *)(step.s6_addr + 8) = htobe64(1llu << (128 - prefix_len)); - else - *(uint64_t *)step.s6_addr = htobe64(1llu << (64 - prefix_len)); + if (name) + list_add_tail(&p->entry, pool_list); - while (in6_addr_cmp(&ip, &end) <= 0) { - it = malloc(sizeof(*it)); - memset(it, 0, sizeof(*it)); - it->pool = pool; - it->it.owner = &ipdb; - INIT_LIST_HEAD(&it->it.prefix_list); - a = malloc(sizeof(*a)); - memset(a, 0, sizeof(*a)); - memcpy(&a->addr, &ip, sizeof(ip)); - a->prefix_len = prefix_len; - list_add_tail(&a->entry, &it->it.prefix_list); - list_add_tail(&it->entry, &pool->items); - in6_addr_add(&ip, &step); + return p; +} + +static struct ip6_pool *find_pool(struct list_head *pool_list, const char *name, int create) +{ + struct ip6_pool *p; + + list_for_each_entry(p, pool_list, entry) { + if (p->name && !strcmp(p->name, name)) + return p; } + + if (create) { + char *dup = _strdup(name); + if (!dup) + return NULL; + return create_pool(pool_list, dup); + } + + return NULL; } -static void add_prefix(enum ippool_type type, struct ippool_t *pool, const char *_val) +/* parse "<addr>/<mask>,<prefix_len>" and append a range to `pool` */ +static void add_prefix(struct ip6_pool *pool, const char *_val) { char *val = _strdup(_val); char *ptr1, *ptr2; - struct in6_addr addr; - int prefix_len; - int mask; + struct in6_addr start, end; + int prefix_len, mask, shift; + uint64_t count; + struct ip6_range *r; + + if (!val) + return; ptr1 = strchr(val, '/'); if (!ptr1) goto err; - *ptr1 = 0; ptr2 = strchr(ptr1 + 1, ','); if (!ptr2) goto err; - *ptr2 = 0; - if (inet_pton(AF_INET6, val, &addr) == 0) + if (inet_pton(AF_INET6, val, &start) == 0) goto err; - if (sscanf(ptr1 + 1, "%i", &mask) != 1) goto err; - if (mask < 7 || mask > 127) goto err; - if (sscanf(ptr2 + 1, "%i", &prefix_len) != 1) goto err; - - if (prefix_len > 128 || prefix_len < mask) + if (prefix_len > 128 || prefix_len < mask) goto err; - if (type == IPPOOL_PREFIX) - generate_dppool(pool, &addr, mask, prefix_len); - else - generate_ippool(pool, &addr, mask, prefix_len); + if (prefix_len - mask > IPPOOL_MAX_SHIFT) { + log_error("ipv6_pool: range '%s' has 2^%d prefixes, exceeds cap 2^%d; skipping\n", + _val, prefix_len - mask, IPPOOL_MAX_SHIFT); + _free(val); + return; + } + + shift = 128 - prefix_len; + + /* end = start | hostmask(mask) (matches the original generator) */ + memcpy(&end, &start, sizeof(end)); + if (mask > 64) + *(uint64_t *)(end.s6_addr + 8) = htobe64(be64toh(*(uint64_t *)(end.s6_addr + 8)) | ((1llu << (128 - mask)) - 1)); + else { + memset(end.s6_addr + 8, 0xff, 8); + *(uint64_t *)end.s6_addr = htobe64(be64toh(*(uint64_t *)end.s6_addr) | ((1llu << (64 - mask)) - 1)); + } + + { + uint8_t delta[16]; + uint64_t span; + in6_sub(delta, end.s6_addr, start.s6_addr); + if (in6_shr_u64(delta, shift, &span) || span >= IPPOOL_MAX_BITS) { + log_error("ipv6_pool: range '%s' exceeds cap; skipping\n", _val); + _free(val); + return; + } + count = span + 1; + } + + r = _malloc(sizeof(*r)); + if (!r) { + _free(val); + return; + } + memset(r, 0, sizeof(*r)); + memcpy(&r->start, &start, sizeof(start)); + r->prefix_len = prefix_len; + r->shift = shift; + r->count = count; + list_add_tail(&r->entry, &pool->ranges); _free(val); return; @@ -245,133 +332,130 @@ err: _free(val); } -static struct ipv6db_item_t *get_ip(struct ap_session *ses) +static int finalize_ranges(struct ip6_pool *p) { - struct ippool_item_t *it; - struct ipv6db_addr_t *a; - struct ippool_t *pool, *start; + struct ip6_range *r; - if (ses->ipv6_pool_name) - pool = find_pool(IPPOOL_ADDRESS, ses->ipv6_pool_name, 0); - else - pool = def_ippool; + list_for_each_entry(r, &p->ranges, entry) { + uint64_t nw = BM_NWORDS(r->count); + uint64_t b; - if (!pool) - return NULL; - - start = pool; - do { - spin_lock(&pool->lock); - if (!list_empty(&pool->items)) { - it = list_entry(pool->items.next, typeof(*it), entry); - list_del(&it->entry); - } else - it = NULL; - spin_unlock(&pool->lock); - - if (it) { - a = list_entry(it->it.addr_list.next, typeof(*a), entry); - if (a->prefix_len == 128) { - memcpy(&it->it.intf_id, conf_gw_addr.s6_addr + 8, 8); - memcpy(&it->it.peer_intf_id, a->addr.s6_addr + 8, 8); - } else { - it->it.intf_id = 0; - it->it.peer_intf_id = 0; - } - - return &it->it; - } - - pool = pool->next; - } while (pool && pool != start); - - return NULL; -} + r->bitmap = _malloc(nw * sizeof(bm_word_t)); + if (!r->bitmap) + return -1; + memset(r->bitmap, 0, nw * sizeof(bm_word_t)); -static void put_ip(struct ap_session *ses, struct ipv6db_item_t *it) -{ - struct ippool_item_t *pit = container_of(it, typeof(*pit), it); + for (b = r->count; b < nw * BM_WORD_BITS; b++) + bm_set(r->bitmap, b); + } - spin_lock(&pit->pool->lock); - list_add_tail(&pit->entry, &pit->pool->items); - spin_unlock(&pit->pool->lock); + return 0; } -static struct ipv6db_prefix_t *get_dp(struct ap_session *ses) +static int parse_line_opts(struct pool_set *set, enum ippool_type type, const char *opt, + struct ip6_pool **pool) { - struct dppool_item_t *it; - struct ippool_t *pool, *start; + struct list_head *pool_list = (type == IPPOOL_PREFIX) ? &set->dppools : &set->ippools; + char *name, *ptr; - if (ses->dpv6_pool_name) - pool = find_pool(IPPOOL_PREFIX, ses->dpv6_pool_name, 0); - else - pool = def_dppool; + name = strstr(opt, ",name="); + if (name) { + name += sizeof(",name=") - 1; + ptr = strchrnul(name, ','); + name = _strndup(name, ptr - name); + if (!name) + return -1; + *pool = find_pool(pool_list, name, 1); + _free(name); + } else + *pool = (type == IPPOOL_PREFIX) ? set->def_dppool : set->def_ippool; - if (!pool) - return NULL; + if (!*pool) + return -1; - start = pool; - do { - spin_lock(&pool->lock); - if (!list_empty(&pool->items)) { - it = list_entry(pool->items.next, typeof(*it), entry); - list_del(&it->entry); - } else - it = NULL; - spin_unlock(&pool->lock); - - if (it) - return &it->it; + name = strstr(opt, ",next="); + if (name) { + struct ip6_pool *next; + name += sizeof(",next=") - 1; + ptr = strchrnul(name, ','); + name = _strndup(name, ptr - name); + if (!name) + return -1; + next = find_pool(pool_list, name, 1); + _free(name); + if (next) + (*pool)->next = next; + } - pool = pool->next; - } while (pool && pool != start); + return 0; +} - return NULL; +static void free_pool(struct ip6_pool *p) +{ + struct ip6_range *r; + + while (!list_empty(&p->ranges)) { + r = list_first_entry(&p->ranges, typeof(*r), entry); + list_del(&r->entry); + if (r->bitmap) + _free(r->bitmap); + _free(r); + } + if (p->name) + _free(p->name); + _free(p); } -static void put_dp(struct ap_session *ses, struct ipv6db_prefix_t *it) +static void free_pool_list(struct list_head *l) { - struct dppool_item_t *pit = container_of(it, typeof(*pit), it); + struct ip6_pool *p; - spin_lock(&pit->pool->lock); - list_add_tail(&pit->entry, &pit->pool->items); - spin_unlock(&pit->pool->lock); + while (!list_empty(l)) { + p = list_first_entry(l, typeof(*p), entry); + list_del(&p->entry); + free_pool(p); + } } -static struct ipdb_t ipdb = { - .get_ipv6 = get_ip, - .put_ipv6 = put_ip, - .get_ipv6_prefix = get_dp, - .put_ipv6_prefix = put_dp, -}; - -#ifdef RADIUS -static void ev_radius_access_accept(struct ev_radius_t *ev) +static void free_pool_set(struct pool_set *set) { - struct rad_attr_t *attr; - struct ap_session *ses = ev->ses; + if (!set) + return; - list_for_each_entry(attr, &ev->reply->attrs, entry) { - if (attr->attr->type != ATTR_TYPE_STRING) - continue; - if (attr->vendor && attr->vendor->id != conf_vendor) - continue; - if (!attr->vendor && conf_vendor) - continue; + free_pool_list(&set->ippools); + free_pool_list(&set->dppools); + if (set->def_ippool) + free_pool(set->def_ippool); + if (set->def_dppool) + free_pool(set->def_dppool); + _free(set); +} - if (conf_dppool_attr && conf_dppool_attr == attr->attr->id) { - if (ses->dpv6_pool_name) - _free(ses->dpv6_pool_name); - ses->dpv6_pool_name = _strdup(attr->val.string); - } else - if (conf_ippool_attr && conf_ippool_attr == attr->attr->id) { - if (ses->ipv6_pool_name) - _free(ses->ipv6_pool_name); - ses->ipv6_pool_name = _strdup(attr->val.string); - } +static int finalize_set(struct pool_set *set) +{ + struct ip6_pool *p; + + if (set->def_ippool && finalize_ranges(set->def_ippool)) + return -1; + if (set->def_dppool && finalize_ranges(set->def_dppool)) + return -1; + list_for_each_entry(p, &set->ippools, entry) { + if (finalize_ranges(p)) + return -1; + if (list_empty(&p->ranges)) + log_warn("ipv6_pool: pool '%s' is empty or not defined\n", p->name); + } + list_for_each_entry(p, &set->dppools, entry) { + if (finalize_ranges(p)) + return -1; + if (list_empty(&p->ranges)) + log_warn("ipv6_pool: delegate pool '%s' is empty or not defined\n", p->name); } + + return 0; } +#ifdef RADIUS static int parse_attr_opt(const char *opt) { struct rad_dict_attr_t *attr; @@ -408,83 +492,77 @@ static int parse_vendor_opt(const char *opt) } #endif -static int parse_options(enum ippool_type type, const char *opt, struct ippool_t **pool, struct ippool_t **next) -{ - char *name, *ptr; - - name = strstr(opt, ",name="); - if (name) { - name += sizeof(",name=") - 1; - ptr = strchrnul(name, ','); - name = _strndup(name, ptr - name); - if (!name) - return -1; - *pool = find_pool(type, name, 1); - } else if (type == IPPOOL_PREFIX) - *pool = def_dppool; - else - *pool = def_ippool; - - name = strstr(opt, ",next="); - if (name) { - name += sizeof(",next=") - 1; - ptr = strchrnul(name, ','); - name = strncpy(alloca(ptr - name + 1), name, ptr - name + 1); - *next = find_pool(type, name, 0); - if (!*next) { - name = _strdup(name); - if (!name) - return -1; - *next = find_pool(type, name, 1); - } - } else - *next = NULL; - - return 0; -} - -static void ippool_init1(void) -{ - ipdb_register(&ipdb); -} - -static void ippool_init2(void) +static struct pool_set *build_pool_set(void) { struct conf_sect_t *s = conf_get_section("ipv6-pool"); struct conf_option_t *opt; - struct ippool_t *pool, *next; - char *val; - enum ippool_type type; + struct pool_set *set; #ifdef RADIUS int dppool_attr = 0, ippool_attr = 0; #endif + set = _malloc(sizeof(*set)); + if (!set) + return NULL; + memset(set, 0, sizeof(*set)); + INIT_LIST_HEAD(&set->ippools); + INIT_LIST_HEAD(&set->dppools); + set->orphan_policy = ORPHAN_KEEP; + +#ifdef RADIUS + /* statics persist across reloads; reset to defaults so a removed + * vendor/attr line doesn't leave stale values behind. A stale + * conf_vendor would otherwise force conf_dppool_attr/conf_ippool_attr + * to 0 below, silently disabling pool-name matching. */ + conf_vendor = 0; + conf_dppool_attr = 171; // Delegated-IPv6-Prefix-Pool + conf_ippool_attr = 172; // Stateful-IPv6-Address-Pool +#endif + if (!s) - return; + return set; - def_ippool = create_pool(IPPOOL_ADDRESS, NULL); - def_dppool = create_pool(IPPOOL_PREFIX, NULL); + set->def_ippool = create_pool(&set->ippools, NULL); + set->def_dppool = create_pool(&set->dppools, NULL); + if (!set->def_ippool || !set->def_dppool) + goto err; list_for_each_entry(opt, &s->items, entry) { + enum ippool_type type; + const char *val; + struct ip6_pool *pool; + #ifdef RADIUS if (triton_module_loaded("radius")) { if (!strcmp(opt->name, "vendor")) { - conf_vendor = parse_vendor_opt(opt->val); + if (opt->val) + conf_vendor = parse_vendor_opt(opt->val); continue; } else if (!strcmp(opt->name, "attr-prefix")) { - dppool_attr = parse_attr_opt(opt->val); + if (opt->val) + dppool_attr = parse_attr_opt(opt->val); continue; } else if (!strcmp(opt->name, "attr-address")) { - ippool_attr = parse_attr_opt(opt->val); + if (opt->val) + ippool_attr = parse_attr_opt(opt->val); continue; } } #endif if (!strcmp(opt->name, "gw-ip6-address")) { - if (inet_pton(AF_INET6, opt->val, &conf_gw_addr) == 0) + if (opt->val && inet_pton(AF_INET6, opt->val, &set->gw_addr) == 0) log_error("ipv6_pool: failed to parse '%s'\n", opt->raw); continue; - } else if (!strcmp(opt->name, "delegate")) { + } + if (!strcmp(opt->name, "reload-orphan")) { + if (opt->val && !strcmp(opt->val, "disconnect")) + set->orphan_policy = ORPHAN_DISCONNECT; + else + set->orphan_policy = ORPHAN_KEEP; + continue; + } + + if (!strcmp(opt->name, "delegate")) { type = IPPOOL_PREFIX; val = opt->val; } else { @@ -492,24 +570,15 @@ static void ippool_init2(void) val = opt->name; } - if (parse_options(type, opt->raw, &pool, &next)) { + if (!val) + continue; + + if (parse_line_opts(set, type, opt->raw, &pool)) { log_error("ipv6_pool: failed to parse '%s'\n", opt->raw); continue; } - add_prefix(type, pool, val); - - if (next) - pool->next = next; - } - - list_for_each_entry(pool, &ippool_list, entry) { - if (list_empty(&pool->items)) - log_warn("ipv6_pool: pool '%s' is empty or not defined\n", pool->name); - } - list_for_each_entry(pool, &dppool_list, entry) { - if (list_empty(&pool->items)) - log_warn("ipv6_pool: delegate pool '%s' is empty or not defined\n", pool->name); + add_prefix(pool, val); } #ifdef RADIUS @@ -518,9 +587,435 @@ static void ippool_init2(void) conf_dppool_attr = dppool_attr; if (conf_vendor || ippool_attr) conf_ippool_attr = ippool_attr; - triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept); } #endif + + if (finalize_set(set)) + goto err; + + return set; + +err: + free_pool_set(set); + return NULL; +} + +/* ===== address lookup ===== */ + +static int pool_contains(struct ip6_pool *p, const struct in6_addr *addr, + struct ip6_range **out_r, uint64_t *out_bit) +{ + struct ip6_range *r; + + list_for_each_entry(r, &p->ranges, entry) { + uint64_t bit = range_addr_to_bit(r, addr); + if (bit != BM_INVALID) { + *out_r = r; + *out_bit = bit; + return 1; + } + } + return 0; +} + +static int find_target(struct list_head *pool_list, struct ip6_pool *def_pool, + const struct in6_addr *addr, const char *pref_name, + struct ip6_pool **op, struct ip6_range **orr, uint64_t *obit) +{ + struct ip6_pool *p; + + if (pref_name) { + p = find_pool(pool_list, pref_name, 0); + if (p && pool_contains(p, addr, orr, obit)) { + *op = p; + return 1; + } + } + + if (def_pool && pool_contains(def_pool, addr, orr, obit)) { + *op = def_pool; + return 1; + } + list_for_each_entry(p, pool_list, entry) { + if (pool_contains(p, addr, orr, obit)) { + *op = p; + return 1; + } + } + + return 0; +} + +/* alloc a free bit from a pool's next-chain; returns range+bit+pool or NULL */ +static struct ip6_range *alloc_from(struct ip6_pool *pool, struct ip6_pool **found_p, uint64_t *found_bit) +{ + struct ip6_pool *start = pool; + struct ip6_range *r, *found_r = NULL; + uint64_t bit = BM_INVALID; + + do { + spin_lock(&pool->lock); + list_for_each_entry(r, &pool->ranges, entry) { + bit = bm_find_free(r->bitmap, r->count, r->cursor); + if (bit != BM_INVALID) { + bm_set(r->bitmap, bit); + r->used++; + r->cursor = bit + 1; + found_r = r; + *found_p = pool; + *found_bit = bit; + break; + } + } + spin_unlock(&pool->lock); + if (found_r) + return found_r; + pool = pool->next; + } while (pool && pool != start); + + return NULL; +} + +/* ===== ipdb get/put: NA ===== */ + +static struct ipv6db_item_t *get_ip(struct ap_session *ses) +{ + struct pool_set *set; + struct ip6_pool *pool, *found_p = NULL; + struct ip6_range *r; + struct ip6_lease *lease; + uint64_t bit; + + pthread_rwlock_rdlock(&pool_set_rwlock); + set = cur_set; + if (!set) { + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } + + pool = ses->ipv6_pool_name ? find_pool(&set->ippools, ses->ipv6_pool_name, 0) : set->def_ippool; + if (!pool) { + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } + + r = alloc_from(pool, &found_p, &bit); + if (!r) { + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } + + lease = _malloc(sizeof(*lease)); + if (!lease) { + spin_lock(&found_p->lock); + bm_clear(r->bitmap, bit); + r->used--; + spin_unlock(&found_p->lock); + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } + + memset(lease, 0, sizeof(*lease)); + lease->pool = found_p; + lease->range = r; + lease->it.owner = &ipdb; + INIT_LIST_HEAD(&lease->it.addr_list); + in6_index_to_addr(&lease->node.addr, &r->start, bit, r->shift); + lease->node.prefix_len = r->prefix_len; + list_add_tail(&lease->node.entry, &lease->it.addr_list); + + if (r->prefix_len == 128) { + memcpy(&lease->it.intf_id, set->gw_addr.s6_addr + 8, 8); + memcpy(&lease->it.peer_intf_id, lease->node.addr.s6_addr + 8, 8); + } else { + lease->it.intf_id = 0; + lease->it.peer_intf_id = 0; + } + + pthread_rwlock_unlock(&pool_set_rwlock); + + return &lease->it; +} + +static void put_ip(struct ap_session *ses, struct ipv6db_item_t *it) +{ + struct ip6_lease *lease = container_of(it, typeof(*lease), it); + + pthread_rwlock_rdlock(&pool_set_rwlock); + if (lease->pool && lease->range) { + uint64_t bit = range_addr_to_bit(lease->range, &lease->node.addr); + spin_lock(&lease->pool->lock); + if (bit != BM_INVALID && bm_test(lease->range->bitmap, bit)) { + bm_clear(lease->range->bitmap, bit); + lease->range->used--; + } + spin_unlock(&lease->pool->lock); + } + pthread_rwlock_unlock(&pool_set_rwlock); + + _free(lease); +} + +/* ===== ipdb get/put: PD ===== */ + +static struct ipv6db_prefix_t *get_dp(struct ap_session *ses) +{ + struct pool_set *set; + struct ip6_pool *pool, *found_p = NULL; + struct ip6_range *r; + struct dp_lease *lease; + uint64_t bit; + + pthread_rwlock_rdlock(&pool_set_rwlock); + set = cur_set; + if (!set) { + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } + + pool = ses->dpv6_pool_name ? find_pool(&set->dppools, ses->dpv6_pool_name, 0) : set->def_dppool; + if (!pool) { + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } + + r = alloc_from(pool, &found_p, &bit); + if (!r) { + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } + + lease = _malloc(sizeof(*lease)); + if (!lease) { + spin_lock(&found_p->lock); + bm_clear(r->bitmap, bit); + r->used--; + spin_unlock(&found_p->lock); + pthread_rwlock_unlock(&pool_set_rwlock); + return NULL; + } + + memset(lease, 0, sizeof(*lease)); + lease->pool = found_p; + lease->range = r; + lease->it.owner = &ipdb; + INIT_LIST_HEAD(&lease->it.prefix_list); + in6_index_to_addr(&lease->node.addr, &r->start, bit, r->shift); + lease->node.prefix_len = r->prefix_len; + list_add_tail(&lease->node.entry, &lease->it.prefix_list); + + pthread_rwlock_unlock(&pool_set_rwlock); + + return &lease->it; +} + +static void put_dp(struct ap_session *ses, struct ipv6db_prefix_t *it) +{ + struct dp_lease *lease = container_of(it, typeof(*lease), it); + + pthread_rwlock_rdlock(&pool_set_rwlock); + if (lease->pool && lease->range) { + uint64_t bit = range_addr_to_bit(lease->range, &lease->node.addr); + spin_lock(&lease->pool->lock); + if (bit != BM_INVALID && bm_test(lease->range->bitmap, bit)) { + bm_clear(lease->range->bitmap, bit); + lease->range->used--; + } + spin_unlock(&lease->pool->lock); + } + pthread_rwlock_unlock(&pool_set_rwlock); + + _free(lease); +} + +static struct ipdb_t ipdb = { + .get_ipv6 = get_ip, + .put_ipv6 = put_ip, + .get_ipv6_prefix = get_dp, + .put_ipv6_prefix = put_dp, +}; + +/* ===== reconcile on reload ===== */ + +static void reserve_bit(struct ip6_pool *np, struct ip6_range *nr, uint64_t bit) +{ + spin_lock(&np->lock); + if (!bm_test(nr->bitmap, bit)) { + bm_set(nr->bitmap, bit); + nr->used++; + } + spin_unlock(&np->lock); +} + +static void reconcile_na(struct pool_set *new_set, struct ap_session *ses, + int policy, struct list_head *disc) +{ + struct ipv6db_item_t *it = ses->ipv6; + struct ip6_pool *np; + struct ip6_range *nr; + uint64_t bit; + + if (!it || !it->owner) + return; + + if (it->owner == &ipdb) { + struct ip6_lease *lease = container_of(it, typeof(*lease), it); + if (find_target(&new_set->ippools, new_set->def_ippool, &lease->node.addr, + ses->ipv6_pool_name, &np, &nr, &bit)) { + reserve_bit(np, nr, bit); + lease->pool = np; + lease->range = nr; + } else { + lease->pool = NULL; + lease->range = NULL; + if (policy == ORPHAN_DISCONNECT) { + struct disc_node *d = _malloc(sizeof(*d)); + if (d) { + d->ses = ses; + list_add_tail(&d->entry, disc); + } + } + } + } else { + struct ipv6db_addr_t *a; + list_for_each_entry(a, &it->addr_list, entry) { + if (find_target(&new_set->ippools, new_set->def_ippool, &a->addr, + NULL, &np, &nr, &bit)) + reserve_bit(np, nr, bit); + } + } +} + +static void reconcile_pd(struct pool_set *new_set, struct ap_session *ses, + int policy, struct list_head *disc) +{ + struct ipv6db_prefix_t *it = ses->ipv6_dp; + struct ip6_pool *np; + struct ip6_range *nr; + uint64_t bit; + + if (!it || !it->owner) + return; + + if (it->owner == &ipdb) { + struct dp_lease *lease = container_of(it, typeof(*lease), it); + if (find_target(&new_set->dppools, new_set->def_dppool, &lease->node.addr, + ses->dpv6_pool_name, &np, &nr, &bit)) { + reserve_bit(np, nr, bit); + lease->pool = np; + lease->range = nr; + } else { + lease->pool = NULL; + lease->range = NULL; + if (policy == ORPHAN_DISCONNECT) { + struct disc_node *d = _malloc(sizeof(*d)); + if (d) { + d->ses = ses; + list_add_tail(&d->entry, disc); + } + } + } + } else { + struct ipv6db_addr_t *a; + list_for_each_entry(a, &it->prefix_list, entry) { + if (find_target(&new_set->dppools, new_set->def_dppool, &a->addr, + NULL, &np, &nr, &bit)) + reserve_bit(np, nr, bit); + } + } +} + +static void terminate_orphan(void *arg) +{ + struct ap_session *ses = arg; + ap_session_terminate(ses, TERM_NAS_REBOOT, 0); +} + +static void load_config(void *data) +{ + struct pool_set *new_set, *old_set; + struct ap_session *ses; + struct disc_node *d; + LIST_HEAD(disc_list); + int policy; + + new_set = build_pool_set(); + if (!new_set) { + log_error("ipv6_pool: reload failed, keeping current pools\n"); + return; + } + policy = new_set->orphan_policy; + + pthread_rwlock_wrlock(&pool_set_rwlock); + pthread_rwlock_rdlock(&ses_lock); + + list_for_each_entry(ses, &ses_list, entry) { + reconcile_na(new_set, ses, policy, &disc_list); + reconcile_pd(new_set, ses, policy, &disc_list); + } + + old_set = cur_set; + cur_set = new_set; + + pthread_rwlock_unlock(&ses_lock); + pthread_rwlock_unlock(&pool_set_rwlock); + + free_pool_set(old_set); + + while (!list_empty(&disc_list)) { + d = list_first_entry(&disc_list, typeof(*d), entry); + list_del(&d->entry); + triton_context_call(d->ses->ctrl->ctx, terminate_orphan, d->ses); + _free(d); + } +} + +#ifdef RADIUS +static void ev_radius_access_accept(struct ev_radius_t *ev) +{ + struct rad_attr_t *attr; + struct ap_session *ses = ev->ses; + + list_for_each_entry(attr, &ev->reply->attrs, entry) { + if (attr->attr->type != ATTR_TYPE_STRING) + continue; + if (attr->vendor && attr->vendor->id != conf_vendor) + continue; + if (!attr->vendor && conf_vendor) + continue; + + if (conf_dppool_attr && conf_dppool_attr == attr->attr->id) { + if (ses->dpv6_pool_name) + _free(ses->dpv6_pool_name); + ses->dpv6_pool_name = _strdup(attr->val.string); + } else if (conf_ippool_attr && conf_ippool_attr == attr->attr->id) { + if (ses->ipv6_pool_name) + _free(ses->ipv6_pool_name); + ses->ipv6_pool_name = _strdup(attr->val.string); + } + } +} +#endif + +/* ===== init ===== */ + +static void ippool_init1(void) +{ + ipdb_register(&ipdb); +} + +static void ippool_init2(void) +{ + load_config(NULL); + + if (triton_event_register_handler(EV_CONFIG_RELOAD, load_config) < 0) + log_error("ipv6_pool: registration of CONFIG_RELOAD event failed," + " pools will not reload\n"); + +#ifdef RADIUS + if (triton_module_loaded("radius")) + triton_event_register_handler(EV_RADIUS_ACCESS_ACCEPT, (triton_event_func)ev_radius_access_accept); +#endif } DEFINE_INIT(51, ippool_init1); diff --git a/accel-pppd/extra/logwtmp.c b/accel-pppd/extra/logwtmp.c index f95b62c4..f66e6403 100644 --- a/accel-pppd/extra/logwtmp.c +++ b/accel-pppd/extra/logwtmp.c @@ -14,6 +14,7 @@ #include "memdebug.h" +#ifdef HAVE_LOGWTMP static void ev_ses_started(struct ap_session *ses) { logwtmp(ses->ifname, ses->username ?: "", ses->ctrl->calling_station_id); @@ -29,5 +30,11 @@ static void init(void) triton_event_register_handler(EV_SES_STARTED, (triton_event_func)ev_ses_started); triton_event_register_handler(EV_SES_FINISHED, (triton_event_func)ev_ses_finished); } +#else +static void init(void) +{ + log_warn("logwtmp is not supported on your platfrom, check libc doc\n"); +} +#endif DEFINE_INIT(200, init); diff --git a/accel-pppd/extra/metrics.c b/accel-pppd/extra/metrics.c new file mode 100644 index 00000000..14e007f8 --- /dev/null +++ b/accel-pppd/extra/metrics.c @@ -0,0 +1,1077 @@ +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <inttypes.h> +#include <errno.h> +#include <fcntl.h> +#include <time.h> +#include <unistd.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <dlfcn.h> + +#include "triton.h" +#include "events.h" +#include "log.h" +#include "list.h" +#include "utils.h" +#include "ap_session.h" +#include "version.h" + +#include "memdebug.h" + +/* Per-protocol session counters live in their respective shared modules. + * Resolve them with dlsym(RTLD_DEFAULT, ...) lazily rather than via direct + * (weak) references: when metrics is dlopen()ed before the protocol module + * the loader binds undefined refs to NULL and never updates them when a + * later RTLD_GLOBAL dlopen brings the symbols in. dlsym walks the live + * global scope at call time, so it picks them up regardless of order. + */ +typedef unsigned int (*proto_stat_fn)(void); + +struct proto_stat { + const char *module; + const char *starting_sym; + const char *active_sym; + proto_stat_fn starting; + proto_stat_fn active; +}; + +static struct proto_stat proto_stats[] = { + { "pppoe", "pppoe_stat_starting", "pppoe_stat_active" }, + { "l2tp", "l2tp_stat_starting", "l2tp_stat_active" }, + { "pptp", "pptp_stat_starting", "pptp_stat_active" }, + { "sstp", "sstp_stat_starting", "sstp_stat_active" }, + { "ipoe", "ipoe_stat_starting", "ipoe_stat_active" }, +}; + +static int proto_resolve(struct proto_stat *p) +{ + if (!triton_module_loaded(p->module)) + return 0; + if (!p->starting) + p->starting = (proto_stat_fn)(uintptr_t)dlsym(RTLD_DEFAULT, p->starting_sym); + if (!p->active) + p->active = (proto_stat_fn)(uintptr_t)dlsym(RTLD_DEFAULT, p->active_sym); + return p->starting && p->active; +} + +enum metrics_format { + METRICS_FORMAT_PROMETHEUS, + METRICS_FORMAT_JSON, +}; + +#define METRICS_RECV_BUF_SIZE 2048 +#define METRICS_DEFAULT_READ_TIMEOUT 5 /* seconds */ +#define METRICS_DEFAULT_MAX_CLIENTS 64 + +struct metrics_client_t { + struct list_head entry; + struct triton_md_handler_t hnd; + struct triton_timer_t timer; + struct sockaddr_in addr; + char *recv_buf; + int recv_pos; + char *xmit_buf; + int xmit_pos; + int xmit_len; + unsigned int disconnect:1; +}; + +struct metrics_acl_t { + struct list_head entry; + uint32_t net; /* host byte order */ + uint32_t mask; /* host byte order */ +}; + +static enum metrics_format conf_format = METRICS_FORMAT_PROMETHEUS; +static char *conf_address; +static LIST_HEAD(conf_allowed); +static int conf_read_timeout = METRICS_DEFAULT_READ_TIMEOUT; +static int conf_max_clients = METRICS_DEFAULT_MAX_CLIENTS; + +#define METRICS_ACCEPT_BACKOFF 1 /* seconds */ +#define METRICS_ACCEPT_BATCH 16 /* max accept()s per serv_read tick */ + +static struct triton_context_t serv_ctx; +static struct triton_md_handler_t serv_hnd; +static struct triton_timer_t accept_resume_timer; +static LIST_HEAD(clients); +static unsigned int client_count; +static int serv_running; +static int accept_paused; + +static int parse_format(const char *opt, enum metrics_format *out) +{ + if (!strcasecmp(opt, "prometheus")) { + *out = METRICS_FORMAT_PROMETHEUS; + return 0; + } + if (!strcasecmp(opt, "json")) { + *out = METRICS_FORMAT_JSON; + return 0; + } + return -1; +} + +/* TODO: IPv6 support. The listener, the ACL, and every sockaddr below are + * IPv4-only for now; bracketed-host syntax ("[::1]:8080"), AF_INET6 sockets, + * and IPv6 CIDRs in allowed_ips are intentionally left for a follow-up. + */ +static int parse_listen_address(const char *str, struct sockaddr_in *addr) +{ + char *buf, *colon; + int port; + int ret = -1; + + buf = strdup(str); + if (!buf) + return -1; + + colon = strrchr(buf, ':'); + if (!colon) + goto out; + + *colon = 0; + port = atoi(colon + 1); + if (port <= 0 || port > 65535) + goto out; + + memset(addr, 0, sizeof(*addr)); + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + if (buf[0] == 0 || !strcmp(buf, "*") || !strcmp(buf, "0.0.0.0")) + addr->sin_addr.s_addr = htonl(INADDR_ANY); + else if (inet_pton(AF_INET, buf, &addr->sin_addr) != 1) + goto out; + + ret = 0; +out: + free(buf); + return ret; +} + +static void free_acl(struct list_head *head) +{ + struct metrics_acl_t *acl; + + while (!list_empty(head)) { + acl = list_first_entry(head, typeof(*acl), entry); + list_del(&acl->entry); + _free(acl); + } +} + +/* Strip surrounding whitespace, optional matching single/double quotes, + * and any trailing comma. Returns NULL if the token becomes empty. + */ +static char *clean_token(char *s) +{ + char *end; + size_t len; + + while (*s == ' ' || *s == '\t') + s++; + + len = strlen(s); + while (len && (s[len - 1] == ' ' || s[len - 1] == '\t' || + s[len - 1] == ',' || s[len - 1] == '\r' || + s[len - 1] == '\n')) + s[--len] = 0; + + if (len >= 2 && ((s[0] == '"' && s[len - 1] == '"') || + (s[0] == '\'' && s[len - 1] == '\''))) { + s[len - 1] = 0; + s++; + len -= 2; + } + + while (*s == ' ' || *s == '\t') + s++; + end = s + strlen(s); + while (end > s && (end[-1] == ' ' || end[-1] == '\t')) + *--end = 0; + + return *s ? s : NULL; +} + +/* TODO: IPv6 support. Only IPv4 CIDR or a bare IPv4 address are accepted; + * IPv6 entries in allowed_ips are rejected at parse time. ip_allowed() and + * struct metrics_acl_t store the network in a 32-bit host-order word, so + * adding IPv6 here will also need the matching widening downstream. + */ +static int parse_acl_entry(const char *str, struct metrics_acl_t **out) +{ + struct metrics_acl_t *acl; + struct in_addr addr; + uint8_t prefix; + uint32_t mask; + + if (!u_parse_ip4cidr(str, &addr, &prefix)) { + /* Accept a bare IP as /32 */ + if (inet_pton(AF_INET, str, &addr) != 1) + return -1; + prefix = 32; + } + + acl = _malloc(sizeof(*acl)); + if (!acl) + return -1; + + mask = prefix ? (uint32_t)0xffffffffu << (32 - prefix) : 0; + acl->net = ntohl(addr.s_addr) & mask; + acl->mask = mask; + *out = acl; + return 0; +} + +/* Parse `allowed_ips` value. Accepts: + * "1.2.3.4/32, 5.6.7.0/24" + * ["1.2.3.4/32", "5.6.7.0/24"] + * On success the supplied list is populated and 0 is returned. Returns -1 on + * any parse error; in that case the partial list is freed. + */ +static int parse_allowed_ips(const char *value, struct list_head *list) +{ + char *buf, *p, *tok; + int ret = -1; + + if (!value || !*value) + return 0; + + buf = strdup(value); + if (!buf) + return -1; + + p = buf; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '[') + p++; + { + size_t len = strlen(p); + while (len && (p[len - 1] == ' ' || p[len - 1] == '\t' || + p[len - 1] == ']' || p[len - 1] == '\r' || + p[len - 1] == '\n')) + p[--len] = 0; + } + + while ((tok = strsep(&p, ",")) != NULL) { + struct metrics_acl_t *acl; + char *clean = clean_token(tok); + + if (!clean) + continue; + if (parse_acl_entry(clean, &acl) < 0) { + log_error("metrics: invalid entry in allowed_ips: '%s'\n", clean); + free_acl(list); + goto out; + } + list_add_tail(&acl->entry, list); + } + + ret = 0; +out: + free(buf); + return ret; +} + +static int ip_allowed(uint32_t addr_nbo) +{ + struct metrics_acl_t *acl; + uint32_t addr; + + if (list_empty(&conf_allowed)) + return 1; + + addr = ntohl(addr_nbo); + list_for_each_entry(acl, &conf_allowed, entry) { + if ((addr & acl->mask) == acl->net) + return 1; + } + return 0; +} + +static int load_config(void) +{ + const char *opt; + enum metrics_format fmt = METRICS_FORMAT_PROMETHEUS; + char *address = NULL; + struct sockaddr_in dummy; + LIST_HEAD(new_allowed); + + opt = conf_get_opt("metrics", "format"); + if (opt && parse_format(opt, &fmt) < 0) { + log_error("metrics: unknown format '%s', expected 'prometheus' or 'json'\n", opt); + return -1; + } + + opt = conf_get_opt("metrics", "address"); + if (!opt) { + log_emerg("metrics: 'address' option is required (host:port)\n"); + return -1; + } + if (parse_listen_address(opt, &dummy) < 0) { + log_emerg("metrics: invalid address '%s', expected host:port\n", opt); + return -1; + } + address = _strdup(opt); + if (!address) { + log_emerg("metrics: out of memory while loading config\n"); + return -1; + } + + opt = conf_get_opt("metrics", "allowed_ips"); + if (opt && parse_allowed_ips(opt, &new_allowed) < 0) { + _free(address); + return -1; + } + + conf_format = fmt; + if (conf_address) + _free(conf_address); + conf_address = address; + + free_acl(&conf_allowed); + list_replace_init(&new_allowed, &conf_allowed); + + opt = conf_get_opt("metrics", "read_timeout"); + if (opt) { + int n = atoi(opt); + conf_read_timeout = n > 0 ? n : 0; + } + + opt = conf_get_opt("metrics", "max_clients"); + if (opt) { + int n = atoi(opt); + conf_max_clients = n > 0 ? n : 0; + } + + return 0; +} + +static const char *content_type(void) +{ + switch (conf_format) { + case METRICS_FORMAT_JSON: + return "application/json"; + case METRICS_FORMAT_PROMETHEUS: + default: + return "text/plain; version=0.0.4; charset=utf-8"; + } +} + +struct strbuf { + char *data; + size_t len; + size_t cap; + int oom; +}; + +static int strbuf_reserve(struct strbuf *sb, size_t want) +{ + size_t need = sb->len + want + 1; + size_t ncap; + char *p; + + if (sb->oom) + return -1; + if (need <= sb->cap) + return 0; + + ncap = sb->cap ? sb->cap : 1024; + while (ncap < need) + ncap *= 2; + + p = _realloc(sb->data, ncap); + if (!p) { + sb->oom = 1; + return -1; + } + sb->data = p; + sb->cap = ncap; + return 0; +} + +static void strbuf_appendf(struct strbuf *sb, const char *fmt, ...) + __attribute__((format(gnu_printf, 2, 3))); + +static void strbuf_appendf(struct strbuf *sb, const char *fmt, ...) +{ + va_list ap; + int n; + char *dst; + size_t avail; + + if (sb->oom) + return; + + for (;;) { + /* On the very first append sb->data is still NULL and + * sb->cap is zero. Computing sb->data + sb->len in that + * state would be NULL pointer arithmetic (UB per the C + * standard); pass NULL directly to vsnprintf instead, + * which is well-defined when the size is zero. + */ + avail = sb->cap - sb->len; + dst = sb->data ? sb->data + sb->len : NULL; + + va_start(ap, fmt); + n = vsnprintf(dst, avail, fmt, ap); + va_end(ap); + + if (n < 0) { + sb->oom = 1; + return; + } + if ((size_t)n < avail) { + sb->len += n; + return; + } + if (strbuf_reserve(sb, n + 1) < 0) + return; + } +} + +static void strbuf_free(struct strbuf *sb) +{ + if (sb->data) + _free(sb->data); + sb->data = NULL; + sb->len = sb->cap = 0; +} + +struct accel_stats { + time_t uptime; + unsigned int cpu; + unsigned long rss_bytes; + unsigned long virt_bytes; + struct triton_stat_t core; + struct ap_session_stat sessions; +}; + +static void read_proc_mem(unsigned long *rss, unsigned long *virt) +{ + char path[64]; + unsigned long vmsize = 0, vmrss = 0; + long page_size = sysconf(_SC_PAGESIZE); + FILE *f; + + snprintf(path, sizeof(path), "/proc/%i/statm", getpid()); + f = fopen(path, "r"); + if (f) { + if (fscanf(f, "%lu %lu", &vmsize, &vmrss) != 2) { + vmsize = 0; + vmrss = 0; + } + fclose(f); + } + + *rss = (unsigned long)vmrss * (page_size > 0 ? page_size : 4096); + *virt = (unsigned long)vmsize * (page_size > 0 ? page_size : 4096); +} + +static void gather_stats(struct accel_stats *s) +{ + struct timespec ts; + + memset(s, 0, sizeof(*s)); + triton_stat_get(&s->core); + ap_session_stat_get(&s->sessions); + + clock_gettime(CLOCK_MONOTONIC, &ts); + s->uptime = ts.tv_sec - s->core.start_time; + s->cpu = s->core.cpu; + + read_proc_mem(&s->rss_bytes, &s->virt_bytes); +} + +static void emit_prom_gauge(struct strbuf *sb, const char *name, + const char *help, unsigned long long value) +{ + strbuf_appendf(sb, "# HELP %s %s\n", name, help); + strbuf_appendf(sb, "# TYPE %s gauge\n", name); + strbuf_appendf(sb, "%s %llu\n", name, value); +} + +static void render_prometheus(struct strbuf *sb) +{ + struct accel_stats s; + + gather_stats(&s); + + strbuf_appendf(sb, "# HELP accel_ppp_build_info accel-ppp build information\n"); + strbuf_appendf(sb, "# TYPE accel_ppp_build_info gauge\n"); + strbuf_appendf(sb, "accel_ppp_build_info{version=\"%s\"} 1\n", ACCEL_PPP_VERSION); + + emit_prom_gauge(sb, "accel_ppp_uptime_seconds", + "Daemon uptime in seconds", + (unsigned long long)s.uptime); + emit_prom_gauge(sb, "accel_ppp_cpu_percent", + "Daemon CPU usage in percent", + (unsigned long long)s.cpu); + emit_prom_gauge(sb, "accel_ppp_memory_rss_bytes", + "Resident set size of the daemon in bytes", + (unsigned long long)s.rss_bytes); + emit_prom_gauge(sb, "accel_ppp_memory_virt_bytes", + "Virtual memory size of the daemon in bytes", + (unsigned long long)s.virt_bytes); + + emit_prom_gauge(sb, "accel_ppp_core_mempool_allocated_bytes", + "Bytes currently allocated from triton mempools", + (unsigned long long)s.core.mempool_allocated); + emit_prom_gauge(sb, "accel_ppp_core_mempool_available_bytes", + "Bytes currently free in triton mempools", + (unsigned long long)s.core.mempool_available); + emit_prom_gauge(sb, "accel_ppp_core_threads", + "Total number of triton worker threads", + s.core.thread_count); + emit_prom_gauge(sb, "accel_ppp_core_threads_active", + "Number of triton worker threads currently active", + s.core.thread_active); + emit_prom_gauge(sb, "accel_ppp_core_contexts", + "Total number of triton contexts", + s.core.context_count); + emit_prom_gauge(sb, "accel_ppp_core_contexts_sleeping", + "Number of triton contexts currently sleeping", + s.core.context_sleeping); + emit_prom_gauge(sb, "accel_ppp_core_contexts_pending", + "Number of triton contexts waiting to run", + s.core.context_pending); + emit_prom_gauge(sb, "accel_ppp_core_md_handlers", + "Total number of triton md handlers", + s.core.md_handler_count); + emit_prom_gauge(sb, "accel_ppp_core_md_handlers_pending", + "Number of triton md handlers with pending events", + s.core.md_handler_pending); + emit_prom_gauge(sb, "accel_ppp_core_timers", + "Total number of triton timers", + s.core.timer_count); + emit_prom_gauge(sb, "accel_ppp_core_timers_pending", + "Number of triton timers pending fire", + s.core.timer_pending); + + strbuf_appendf(sb, "# HELP accel_ppp_sessions Number of sessions in each state\n"); + strbuf_appendf(sb, "# TYPE accel_ppp_sessions gauge\n"); + strbuf_appendf(sb, "accel_ppp_sessions{state=\"starting\"} %u\n", s.sessions.starting); + strbuf_appendf(sb, "accel_ppp_sessions{state=\"active\"} %u\n", s.sessions.active); + strbuf_appendf(sb, "accel_ppp_sessions{state=\"finishing\"} %u\n", s.sessions.finishing); + + strbuf_appendf(sb, "# HELP accel_ppp_protocol_sessions Sessions per protocol and state\n"); + strbuf_appendf(sb, "# TYPE accel_ppp_protocol_sessions gauge\n"); + for (size_t i = 0; i < sizeof(proto_stats) / sizeof(proto_stats[0]); i++) { + struct proto_stat *p = &proto_stats[i]; + + if (!proto_resolve(p)) + continue; + strbuf_appendf(sb, "accel_ppp_protocol_sessions{protocol=\"%s\",state=\"starting\"} %u\n", + p->module, p->starting()); + strbuf_appendf(sb, "accel_ppp_protocol_sessions{protocol=\"%s\",state=\"active\"} %u\n", + p->module, p->active()); + } +} + +static void append_json_string(struct strbuf *sb, const char *s) +{ + strbuf_appendf(sb, "\""); + for (; *s; s++) { + switch (*s) { + case '"': + strbuf_appendf(sb, "\\\""); + break; + case '\\': + strbuf_appendf(sb, "\\\\"); + break; + case '\b': + strbuf_appendf(sb, "\\b"); + break; + case '\f': + strbuf_appendf(sb, "\\f"); + break; + case '\n': + strbuf_appendf(sb, "\\n"); + break; + case '\r': + strbuf_appendf(sb, "\\r"); + break; + case '\t': + strbuf_appendf(sb, "\\t"); + break; + default: + if ((unsigned char)*s < 0x20) + strbuf_appendf(sb, "\\u%04x", (unsigned)*s); + else + strbuf_appendf(sb, "%c", *s); + break; + } + } + strbuf_appendf(sb, "\""); +} + +static void emit_json_proto(struct strbuf *sb, const char *name, int *first, + unsigned int starting, unsigned int active) +{ + if (!*first) + strbuf_appendf(sb, ","); + *first = 0; + strbuf_appendf(sb, "\"%s\":{\"starting\":%u,\"active\":%u}", + name, starting, active); +} + +static void render_json(struct strbuf *sb) +{ + struct accel_stats s; + int first = 1; + + gather_stats(&s); + + strbuf_appendf(sb, "{"); + strbuf_appendf(sb, "\"build\":{\"version\":"); + append_json_string(sb, ACCEL_PPP_VERSION); + strbuf_appendf(sb, "},"); + + strbuf_appendf(sb, "\"uptime_seconds\":%llu,", (unsigned long long)s.uptime); + strbuf_appendf(sb, "\"cpu_percent\":%u,", s.cpu); + strbuf_appendf(sb, "\"memory\":{\"rss_bytes\":%lu,\"virt_bytes\":%lu},", + s.rss_bytes, s.virt_bytes); + + strbuf_appendf(sb, "\"core\":{"); + strbuf_appendf(sb, "\"mempool_allocated_bytes\":%" PRIu64 ",", s.core.mempool_allocated); + strbuf_appendf(sb, "\"mempool_available_bytes\":%" PRIu64 ",", s.core.mempool_available); + strbuf_appendf(sb, "\"threads\":%u,", s.core.thread_count); + strbuf_appendf(sb, "\"threads_active\":%u,", s.core.thread_active); + strbuf_appendf(sb, "\"contexts\":%u,", s.core.context_count); + strbuf_appendf(sb, "\"contexts_sleeping\":%u,", s.core.context_sleeping); + strbuf_appendf(sb, "\"contexts_pending\":%u,", s.core.context_pending); + strbuf_appendf(sb, "\"md_handlers\":%u,", s.core.md_handler_count); + strbuf_appendf(sb, "\"md_handlers_pending\":%u,", s.core.md_handler_pending); + strbuf_appendf(sb, "\"timers\":%u,", s.core.timer_count); + strbuf_appendf(sb, "\"timers_pending\":%u", s.core.timer_pending); + strbuf_appendf(sb, "},"); + + strbuf_appendf(sb, + "\"sessions\":{\"starting\":%u,\"active\":%u,\"finishing\":%u},", + s.sessions.starting, s.sessions.active, s.sessions.finishing); + + strbuf_appendf(sb, "\"protocols\":{"); + for (size_t i = 0; i < sizeof(proto_stats) / sizeof(proto_stats[0]); i++) { + struct proto_stat *p = &proto_stats[i]; + + if (!proto_resolve(p)) + continue; + emit_json_proto(sb, p->module, &first, p->starting(), p->active()); + } + strbuf_appendf(sb, "}"); + + strbuf_appendf(sb, "}\n"); +} + +/* Try to drain cln->xmit_buf to the socket. Returns 0 if the entire + * response was flushed, 1 if a partial write occurred and MD_MODE_WRITE + * was enabled to finish later, -1 if the connection is broken (caller + * should disconnect). + */ +static int xmit_flush(struct metrics_client_t *cln) +{ + int n; + + while (cln->xmit_pos < cln->xmit_len) { + n = write(cln->hnd.fd, + cln->xmit_buf + cln->xmit_pos, + cln->xmit_len - cln->xmit_pos); + if (n < 0) { + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + triton_md_enable_handler(&cln->hnd, MD_MODE_WRITE); + return 1; + } + return -1; + } + cln->xmit_pos += n; + } + return 0; +} + +static void send_response(struct metrics_client_t *cln, int status, const char *reason, + const char *ctype, const char *body, int body_len) +{ + char header[256]; + int hlen, total; + int rc; + + if (cln->xmit_buf) + return; /* response already in flight */ + + hlen = snprintf(header, sizeof(header), + "HTTP/1.1 %d %s\r\n" + "Server: accel-ppp\r\n" + "Content-Type: %s\r\n" + "Content-Length: %d\r\n" + "Connection: close\r\n" + "\r\n", + status, reason, ctype, body_len); + if (hlen <= 0 || hlen >= (int)sizeof(header)) { + cln->disconnect = 1; + return; + } + + total = hlen + (body_len > 0 ? body_len : 0); + cln->xmit_buf = _malloc(total); + if (!cln->xmit_buf) { + cln->disconnect = 1; + return; + } + memcpy(cln->xmit_buf, header, hlen); + if (body_len > 0) + memcpy(cln->xmit_buf + hlen, body, body_len); + cln->xmit_pos = 0; + cln->xmit_len = total; + + rc = xmit_flush(cln); + if (rc < 0) + cln->disconnect = 1; + else if (rc == 0) + cln->disconnect = 1; /* fully flushed, ready to close */ +} + +static void send_simple(struct metrics_client_t *cln, int status, const char *reason) +{ + char body[128]; + int len; + + len = snprintf(body, sizeof(body), "%d %s\n", status, reason); + send_response(cln, status, reason, "text/plain; charset=utf-8", body, len); +} + +static void serve_metrics(struct metrics_client_t *cln) +{ + struct strbuf sb = {0}; + + switch (conf_format) { + case METRICS_FORMAT_PROMETHEUS: + render_prometheus(&sb); + break; + case METRICS_FORMAT_JSON: + render_json(&sb); + break; + } + + if (sb.oom || !sb.data) { + send_simple(cln, 500, "Internal Server Error"); + goto out; + } + + send_response(cln, 200, "OK", content_type(), sb.data, (int)sb.len); +out: + strbuf_free(&sb); +} + +static void client_timeout(struct triton_timer_t *t); + +static void disconnect_client(struct metrics_client_t *cln) +{ + if (cln->timer.tpd) + triton_timer_del(&cln->timer); + list_del(&cln->entry); + client_count--; + triton_md_unregister_handler(&cln->hnd, 1); + if (cln->recv_buf) + _free(cln->recv_buf); + if (cln->xmit_buf) + _free(cln->xmit_buf); + _free(cln); +} + +static void client_timeout(struct triton_timer_t *t) +{ + struct metrics_client_t *cln = container_of(t, typeof(*cln), timer); + + disconnect_client(cln); +} + +static void handle_request(struct metrics_client_t *cln) +{ + char *line_end, *space1, *space2; + char *method, *path; + + line_end = strstr(cln->recv_buf, "\r\n"); + if (!line_end) + return; + *line_end = 0; + + method = cln->recv_buf; + space1 = strchr(method, ' '); + if (!space1) { + send_simple(cln, 400, "Bad Request"); + return; + } + *space1 = 0; + path = space1 + 1; + space2 = strchr(path, ' '); + if (space2) + *space2 = 0; + + if (strcmp(method, "GET")) { + send_simple(cln, 405, "Method Not Allowed"); + return; + } + + if (!strcmp(path, "/metrics")) + serve_metrics(cln); + else + send_simple(cln, 404, "Not Found"); +} + +static int cln_read(struct triton_md_handler_t *h) +{ + struct metrics_client_t *cln = container_of(h, typeof(*cln), hnd); + int n; + + while (1) { + if (cln->recv_pos >= METRICS_RECV_BUF_SIZE - 1) { + send_simple(cln, 413, "Request Entity Too Large"); + break; + } + + n = read(h->fd, cln->recv_buf + cln->recv_pos, + METRICS_RECV_BUF_SIZE - 1 - cln->recv_pos); + if (n == 0) { + cln->disconnect = 1; + break; + } + if (n < 0) { + if (errno == EAGAIN) + return 0; + cln->disconnect = 1; + break; + } + + cln->recv_pos += n; + cln->recv_buf[cln->recv_pos] = 0; + + if (strstr(cln->recv_buf, "\r\n\r\n")) { + handle_request(cln); + break; + } + } + + if (cln->disconnect) { + disconnect_client(cln); + return -1; + } + if (cln->xmit_buf) + triton_md_disable_handler(&cln->hnd, MD_MODE_READ); + return 0; +} + +static int cln_write(struct triton_md_handler_t *h) +{ + struct metrics_client_t *cln = container_of(h, typeof(*cln), hnd); + int rc; + + rc = xmit_flush(cln); + if (rc == 1) + return 0; /* still partial — keep MD_MODE_WRITE enabled */ + if (rc < 0) { + disconnect_client(cln); + return -1; + } + triton_md_disable_handler(&cln->hnd, MD_MODE_WRITE); + disconnect_client(cln); + return -1; +} + +static void accept_resume(struct triton_timer_t *t) +{ + triton_timer_del(t); + accept_paused = 0; + triton_md_enable_handler(&serv_hnd, MD_MODE_READ); +} + +static void accept_pause(void) +{ + if (accept_paused) + return; + accept_paused = 1; + triton_md_disable_handler(&serv_hnd, MD_MODE_READ); + accept_resume_timer.expire = accept_resume; + accept_resume_timer.expire_tv.tv_sec = METRICS_ACCEPT_BACKOFF; + triton_timer_add(&serv_ctx, &accept_resume_timer, 0); +} + +static int serv_read(struct triton_md_handler_t *h) +{ + struct sockaddr_in addr; + socklen_t size = sizeof(addr); + int sock; + struct metrics_client_t *cln; + int batch; + + /* Cap the number of accepts handled per dispatch. Without this, an + * overflow burst (peers exceeding max_clients or denied by + * allowed_ips) keeps us in this loop accept()ing and immediately + * closing sockets, never yielding back to the triton dispatcher. + * Since the per-client read-timeout timers share serv_ctx, that + * would delay client_timeout() and let stalled clients live past + * read_timeout. Return after METRICS_ACCEPT_BATCH iterations; if + * the listening fd is still readable triton will dispatch us again + * on the next loop after timers have had a chance to fire. + */ + for (batch = 0; batch < METRICS_ACCEPT_BATCH; batch++) { + sock = accept(h->fd, (struct sockaddr *)&addr, &size); + if (sock < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return 0; + if (errno == EINTR || errno == ECONNABORTED) + continue; + /* For persistent resource-exhaustion errors + * (EMFILE, ENFILE, ENOBUFS, ENOMEM) the kernel will + * keep the listening fd readable, so a bare + * `continue` spins the worker. Disable the listener + * briefly and retry via a one-shot timer. + */ + log_error("metrics: accept failed: %s; backing off %ds\n", + strerror(errno), METRICS_ACCEPT_BACKOFF); + accept_pause(); + return 0; + } + + if (!ip_allowed(addr.sin_addr.s_addr)) { + close(sock); + continue; + } + + if (conf_max_clients && client_count >= (unsigned int)conf_max_clients) { + close(sock); + continue; + } + + if (fcntl(sock, F_SETFL, O_NONBLOCK)) { + log_error("metrics: failed to set nonblocking mode: %s\n", strerror(errno)); + close(sock); + continue; + } + + cln = _malloc(sizeof(*cln)); + if (!cln) { + close(sock); + continue; + } + memset(cln, 0, sizeof(*cln)); + cln->addr = addr; + cln->hnd.fd = sock; + cln->hnd.read = cln_read; + cln->hnd.write = cln_write; + cln->recv_buf = _malloc(METRICS_RECV_BUF_SIZE); + if (!cln->recv_buf) { + close(sock); + _free(cln); + continue; + } + + list_add_tail(&cln->entry, &clients); + client_count++; + triton_md_register_handler(&serv_ctx, &cln->hnd); + triton_md_enable_handler(&cln->hnd, MD_MODE_READ); + + if (conf_read_timeout > 0) { + cln->timer.expire = client_timeout; + cln->timer.expire_tv.tv_sec = conf_read_timeout; + triton_timer_add(&serv_ctx, &cln->timer, 0); + } + } + + return 0; +} + +static void serv_close(struct triton_context_t *ctx) +{ + struct metrics_client_t *cln; + + if (accept_resume_timer.tpd) + triton_timer_del(&accept_resume_timer); + + while (!list_empty(&clients)) { + cln = list_entry(clients.next, typeof(*cln), entry); + disconnect_client(cln); + } + + triton_md_unregister_handler(&serv_hnd, 1); + triton_context_unregister(ctx); +} + +static struct triton_context_t serv_ctx = { + .close = serv_close, +}; + +static struct triton_md_handler_t serv_hnd = { + .read = serv_read, +}; + +static int start_server(void) +{ + struct sockaddr_in addr; + int reuse = 1; + + if (parse_listen_address(conf_address, &addr) < 0) { + log_emerg("metrics: invalid listen address '%s'\n", conf_address); + return -1; + } + + serv_hnd.fd = socket(PF_INET, SOCK_STREAM, 0); + if (serv_hnd.fd < 0) { + log_emerg("metrics: failed to create socket: %s\n", strerror(errno)); + return -1; + } + + fcntl(serv_hnd.fd, F_SETFD, fcntl(serv_hnd.fd, F_GETFD) | FD_CLOEXEC); + setsockopt(serv_hnd.fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); + + if (bind(serv_hnd.fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + log_emerg("metrics: failed to bind %s: %s\n", conf_address, strerror(errno)); + goto err; + } + + if (listen(serv_hnd.fd, 16) < 0) { + log_emerg("metrics: failed to listen on %s: %s\n", conf_address, strerror(errno)); + goto err; + } + + if (fcntl(serv_hnd.fd, F_SETFL, O_NONBLOCK)) { + log_emerg("metrics: failed to set nonblocking mode: %s\n", strerror(errno)); + goto err; + } + + triton_context_register(&serv_ctx, NULL); + triton_context_set_priority(&serv_ctx, 0); + triton_md_register_handler(&serv_ctx, &serv_hnd); + triton_md_enable_handler(&serv_hnd, MD_MODE_READ); + triton_context_wakeup(&serv_ctx); + + serv_running = 1; + return 0; + +err: + close(serv_hnd.fd); + serv_hnd.fd = -1; + return -1; +} + +static void init(void) +{ + if (load_config() < 0) + return; + + if (start_server() < 0) + return; + + log_info2("metrics: listening on %s, format %s\n", + conf_address, + conf_format == METRICS_FORMAT_PROMETHEUS ? "prometheus" : "json"); +} + +DEFINE_INIT(100, init); diff --git a/accel-pppd/extra/net-snmp/statCore.c b/accel-pppd/extra/net-snmp/statCore.c index c2e64689..7e9047da 100644 --- a/accel-pppd/extra/net-snmp/statCore.c +++ b/accel-pppd/extra/net-snmp/statCore.c @@ -49,7 +49,7 @@ handle_statCoreUpTime(netsnmp_mib_handler *handler, struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); - ts.tv_sec -= triton_stat.start_time; + ts.tv_sec -= triton_stat_start_time(); /* We are never called for a GETNEXT if it's registered as a "instance", as it's "magically" handled for us. */ @@ -80,6 +80,8 @@ handle_statCoreCPU(netsnmp_mib_handler *handler, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { + long cpu; + /* We are never called for a GETNEXT if it's registered as a "instance", as it's "magically" handled for us. */ @@ -89,9 +91,10 @@ handle_statCoreCPU(netsnmp_mib_handler *handler, switch(reqinfo->mode) { case MODE_GET: + cpu = triton_stat_cpu(); snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, - (u_char *)&triton_stat.cpu /* XXX: a pointer to the scalar's data */, - sizeof(triton_stat.cpu)/* XXX: the length of the data in bytes */); + (u_char *)&cpu /* XXX: a pointer to the scalar's data */, + sizeof(cpu)/* XXX: the length of the data in bytes */); break; diff --git a/accel-pppd/extra/net-snmp/statIPOE.c b/accel-pppd/extra/net-snmp/statIPOE.c index 24f154fd..33430fe6 100644 --- a/accel-pppd/extra/net-snmp/statIPOE.c +++ b/accel-pppd/extra/net-snmp/statIPOE.c @@ -8,18 +8,17 @@ #include <net-snmp/agent/net-snmp-agent-includes.h> #include "triton.h" +#include "accel-pppd/ctrl/ipoe/ipoe.h" #include "statIPOE.h" -/* - * The variables we want to tie the relevant OIDs to. - * The agent will handle all GET and (if applicable) SET requests - * to these variables automatically, changing the values as needed. - */ - -void ipoe_get_stat(unsigned int **, unsigned int **); - -static unsigned int *stat_starting; -static unsigned int *stat_active; +static int handle_statIPOEStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); +static int handle_statIPOEActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); /* * Our initialization routine, called automatically by the agent @@ -28,9 +27,6 @@ static unsigned int *stat_active; void init_statIPOE(void) { - netsnmp_handler_registration *reg; - netsnmp_watcher_info *winfo; - static oid statIPOEStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,6,1 }; static oid statIPOEActive_oid[] = { 1,3,6,1,4,1,8072,100,1,6,2 }; @@ -43,51 +39,75 @@ init_statIPOE(void) if (!triton_module_loaded("ipoe")) return; - ipoe_get_stat(&stat_starting, &stat_active); - - /* - * Register scalar watchers for each of the MIB objects. - * The ASN type and RO/RW status are taken from the MIB definition, - * but can be adjusted if needed. - * - * In most circumstances, the scalar watcher will handle all - * of the necessary processing. But the NULL parameter in the - * netsnmp_create_handler_registration() call can be used to - * supply a user-provided handler if necessary. - * - * This approach can also be used to handle Counter64, string- - * and OID-based watched scalars (although variable-sized writeable - * objects will need some more specialised initialisation). - */ DEBUGMSGTL(("statIPOE", "Initializing statIPOEStarting scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statIPOEStarting", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statIPOEStarting", handle_statIPOEStarting, statIPOEStarting_oid, OID_LENGTH(statIPOEStarting_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_starting, sizeof(*stat_starting), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statIPOEStarting" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statIPOEStarting" ); } DEBUGMSGTL(("statIPOE", "Initializing statIPOEActive scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statIPOEActive", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statIPOEActive", handle_statIPOEActive, statIPOEActive_oid, OID_LENGTH(statIPOEActive_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_active, sizeof(*stat_active), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statIPOEActive" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statIPOEActive" ); } DEBUGMSGTL(("statIPOE", "Done initalizing statIPOE module\n")); } + +static int handle_statIPOEStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = ipoe_stat_starting(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statIPOEStarting\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + +static int handle_statIPOEActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = ipoe_stat_active(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statIPOEActive\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} diff --git a/accel-pppd/extra/net-snmp/statL2TP.c b/accel-pppd/extra/net-snmp/statL2TP.c index 59998386..36e6f90b 100644 --- a/accel-pppd/extra/net-snmp/statL2TP.c +++ b/accel-pppd/extra/net-snmp/statL2TP.c @@ -8,19 +8,18 @@ #include <net-snmp/agent/net-snmp-agent-includes.h> #include "triton.h" +#include "accel-pppd/ctrl/l2tp/l2tp.h" #include "statL2TP.h" -/* - * The variables we want to tie the relevant OIDs to. - * The agent will handle all GET and (if applicable) SET requests - * to these variables automatically, changing the values as needed. - */ - -void l2tp_get_stat(unsigned int **, unsigned int **); - -static unsigned int *stat_starting; -static unsigned int *stat_active; +static int handle_statL2TPStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); +static int handle_statL2TPActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); /* * Our initialization routine, called automatically by the agent @@ -29,9 +28,6 @@ static unsigned int *stat_active; void init_statL2TP(void) { - netsnmp_handler_registration *reg; - netsnmp_watcher_info *winfo; - static oid statL2TPStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,4,1 }; static oid statL2TPActive_oid[] = { 1,3,6,1,4,1,8072,100,1,4,2 }; @@ -44,51 +40,75 @@ init_statL2TP(void) if (!triton_module_loaded("l2tp")) return; - l2tp_get_stat(&stat_starting, &stat_active); - - /* - * Register scalar watchers for each of the MIB objects. - * The ASN type and RO/RW status are taken from the MIB definition, - * but can be adjusted if needed. - * - * In most circumstances, the scalar watcher will handle all - * of the necessary processing. But the NULL parameter in the - * netsnmp_create_handler_registration() call can be used to - * supply a user-provided handler if necessary. - * - * This approach can also be used to handle Counter64, string- - * and OID-based watched scalars (although variable-sized writeable - * objects will need some more specialised initialisation). - */ DEBUGMSGTL(("statL2TP", "Initializing statL2TPStarting scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statL2TPStarting", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statL2TPStarting", handle_statL2TPStarting, statL2TPStarting_oid, OID_LENGTH(statL2TPStarting_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_starting, sizeof(*stat_starting), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statL2TPStarting" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statL2TPStarting" ); } DEBUGMSGTL(("statL2TP", "Initializing statL2TPActive scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statL2TPActive", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statL2TPActive", handle_statL2TPActive, statL2TPActive_oid, OID_LENGTH(statL2TPActive_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_active, sizeof(*stat_active), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statL2TPActive" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statL2TPActive" ); } DEBUGMSGTL(("statL2TP", "Done initalizing statL2TP module\n")); } + +static int handle_statL2TPStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = l2tp_stat_starting(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statL2TPStarting\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + +static int handle_statL2TPActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = l2tp_stat_active(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statL2TPActive\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} diff --git a/accel-pppd/extra/net-snmp/statPPP.c b/accel-pppd/extra/net-snmp/statPPP.c index 37e4630c..7dc1f659 100644 --- a/accel-pppd/extra/net-snmp/statPPP.c +++ b/accel-pppd/extra/net-snmp/statPPP.c @@ -6,9 +6,22 @@ #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include <net-snmp/agent/net-snmp-agent-includes.h> + +#include "ap_session.h" #include "statPPP.h" -#include "ppp.h" +static int handle_statPPPStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); +static int handle_statPPPActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); +static int handle_statPPPFinishing(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); /* * Our initialization routine, called automatically by the agent @@ -17,77 +30,115 @@ void init_statPPP(void) { - netsnmp_handler_registration *reg; - netsnmp_watcher_info *winfo; - static oid statPPPStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,2,1 }; static oid statPPPActive_oid[] = { 1,3,6,1,4,1,8072,100,1,2,2 }; static oid statPPPFinishing_oid[] = { 1,3,6,1,4,1,8072,100,1,2,3 }; - /* - * a debugging statement. Run the agent with -DstatPPP to see - * the output of this debugging statement. - */ DEBUGMSGTL(("statPPP", "Initializing the statPPP module\n")); - - /* - * Register scalar watchers for each of the MIB objects. - * The ASN type and RO/RW status are taken from the MIB definition, - * but can be adjusted if needed. - * - * In most circumstances, the scalar watcher will handle all - * of the necessary processing. But the NULL parameter in the - * netsnmp_create_handler_registration() call can be used to - * supply a user-provided handler if necessary. - * - * This approach can also be used to handle Counter64, string- - * and OID-based watched scalars (although variable-sized writeable - * objects will need some more specialised initialisation). - */ DEBUGMSGTL(("statPPP", "Initializing statPPPStarting scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statPPPStarting", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statPPPStarting", handle_statPPPStarting, statPPPStarting_oid, OID_LENGTH(statPPPStarting_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - &ap_session_stat.starting, sizeof(ap_session_stat.starting), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statPPPStarting" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statPPPStarting" ); } DEBUGMSGTL(("statPPP", "Initializing statPPPActive scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statPPPActive", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statPPPActive", handle_statPPPActive, statPPPActive_oid, OID_LENGTH(statPPPActive_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - &ap_session_stat.active, sizeof(ap_session_stat.active), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statPPPActive" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statPPPActive" ); } DEBUGMSGTL(("statPPP", "Initializing statPPPFinishing scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statPPPFinishing", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statPPPFinishing", handle_statPPPFinishing, statPPPFinishing_oid, OID_LENGTH(statPPPFinishing_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - &ap_session_stat.finishing, sizeof(ap_session_stat.finishing), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statPPPFinishing" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statPPPFinishing" ); } DEBUGMSGTL(("statPPP", "Done initalizing statPPP module\n")); } + +static int handle_statPPPStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = ap_session_stat_starting(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statPPPStarting\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + +static int handle_statPPPActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = ap_session_stat_active(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statPPPActive\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + +static int handle_statPPPFinishing(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = ap_session_stat_finishing(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statPPPFinishing\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} diff --git a/accel-pppd/extra/net-snmp/statPPPOE.c b/accel-pppd/extra/net-snmp/statPPPOE.c index 6042dc5b..64e61c3c 100644 --- a/accel-pppd/extra/net-snmp/statPPPOE.c +++ b/accel-pppd/extra/net-snmp/statPPPOE.c @@ -10,16 +10,17 @@ #include "triton.h" #include "statPPPOE.h" -/* - * The variables we want to tie the relevant OIDs to. - * The agent will handle all GET and (if applicable) SET requests - * to these variables automatically, changing the values as needed. - */ +unsigned int pppoe_stat_starting(void); +unsigned int pppoe_stat_active(void); -void pppoe_get_stat(unsigned int **, unsigned int **); - -static unsigned int *stat_starting; -static unsigned int *stat_active; +static int handle_statPPPOEStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); +static int handle_statPPPOEActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); /* * Our initialization routine, called automatically by the agent @@ -28,9 +29,6 @@ static unsigned int *stat_active; void init_statPPPOE(void) { - netsnmp_handler_registration *reg; - netsnmp_watcher_info *winfo; - static oid statPPPOEStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,5,1 }; static oid statPPPOEActive_oid[] = { 1,3,6,1,4,1,8072,100,1,5,2 }; @@ -43,51 +41,69 @@ init_statPPPOE(void) if (!triton_module_loaded("pppoe")) return; - pppoe_get_stat(&stat_starting, &stat_active); - - /* - * Register scalar watchers for each of the MIB objects. - * The ASN type and RO/RW status are taken from the MIB definition, - * but can be adjusted if needed. - * - * In most circumstances, the scalar watcher will handle all - * of the necessary processing. But the NULL parameter in the - * netsnmp_create_handler_registration() call can be used to - * supply a user-provided handler if necessary. - * - * This approach can also be used to handle Counter64, string- - * and OID-based watched scalars (although variable-sized writeable - * objects will need some more specialised initialisation). - */ DEBUGMSGTL(("statPPPOE", "Initializing statPPPOEStarting scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statPPPOEStarting", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statPPPOEStarting", handle_statPPPOEStarting, statPPPOEStarting_oid, OID_LENGTH(statPPPOEStarting_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_starting, sizeof(*stat_starting), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statPPPOEStarting" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statPPPOEStarting" ); } DEBUGMSGTL(("statPPPOE", "Initializing statPPPOEActive scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statPPPOEActive", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statPPPOEActive", handle_statPPPOEActive, statPPPOEActive_oid, OID_LENGTH(statPPPOEActive_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_active, sizeof(*stat_active), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statPPPOEActive" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statPPPOEActive" ); } DEBUGMSGTL(("statPPPOE", - "Done initalizing statPPPOE module\n")); + "Done initalizing statPPPOE module\n")); +} + +static int handle_statPPPOEStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + switch (reqinfo->mode) { + case MODE_GET: + stat = pppoe_stat_starting(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statPPPOEStarting\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + +static int handle_statPPPOEActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + switch (reqinfo->mode) { + case MODE_GET: + stat = pppoe_stat_active(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statPPPOEActive\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; } diff --git a/accel-pppd/extra/net-snmp/statPPTP.c b/accel-pppd/extra/net-snmp/statPPTP.c index 48642202..8a633da3 100644 --- a/accel-pppd/extra/net-snmp/statPPTP.c +++ b/accel-pppd/extra/net-snmp/statPPTP.c @@ -6,20 +6,19 @@ #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> #include <net-snmp/agent/net-snmp-agent-includes.h> -#include "statPPTP.h" #include "triton.h" +#include "accel-pppd/ctrl/pptp/pptp.h" +#include "statPPTP.h" -/* - * The variables we want to tie the relevant OIDs to. - * The agent will handle all GET and (if applicable) SET requests - * to these variables automatically, changing the values as needed. - */ - -void pptp_get_stat(unsigned int **, unsigned int **); - -static unsigned int *stat_starting; -static unsigned int *stat_active; +static int handle_statPPTPStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); +static int handle_statPPTPActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); /* * Our initialization routine, called automatically by the agent @@ -28,9 +27,6 @@ static unsigned int *stat_active; void init_statPPTP(void) { - netsnmp_handler_registration *reg; - netsnmp_watcher_info *winfo; - static oid statPPTPStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,3,1 }; static oid statPPTPActive_oid[] = { 1,3,6,1,4,1,8072,100,1,3,2 }; @@ -43,50 +39,75 @@ init_statPPTP(void) if (!triton_module_loaded("pptp")) return; - pptp_get_stat(&stat_starting, &stat_active); - /* - * Register scalar watchers for each of the MIB objects. - * The ASN type and RO/RW status are taken from the MIB definition, - * but can be adjusted if needed. - * - * In most circumstances, the scalar watcher will handle all - * of the necessary processing. But the NULL parameter in the - * netsnmp_create_handler_registration() call can be used to - * supply a user-provided handler if necessary. - * - * This approach can also be used to handle Counter64, string- - * and OID-based watched scalars (although variable-sized writeable - * objects will need some more specialised initialisation). - */ DEBUGMSGTL(("statPPTP", "Initializing statPPTPStarting scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statPPTPStarting", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statPPTPStarting", handle_statPPTPStarting, statPPTPStarting_oid, OID_LENGTH(statPPTPStarting_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_starting, sizeof(*stat_starting), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statPPTPStarting" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statPPTPStarting" ); } DEBUGMSGTL(("statPPTP", "Initializing statPPTPActive scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statPPTPActive", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statPPTPActive", handle_statPPTPActive, statPPTPActive_oid, OID_LENGTH(statPPTPActive_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_active, sizeof(*stat_active), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statPPTPActive" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statPPTPActive" ); } DEBUGMSGTL(("statPPTP", "Done initalizing statPPTP module\n")); } + +static int handle_statPPTPStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = pptp_stat_starting(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statPPTPStarting\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + +static int handle_statPPTPActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = pptp_stat_active(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statPPTPActive\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} diff --git a/accel-pppd/extra/net-snmp/statSSTP.c b/accel-pppd/extra/net-snmp/statSSTP.c index 06ba6aa1..62948acd 100644 --- a/accel-pppd/extra/net-snmp/statSSTP.c +++ b/accel-pppd/extra/net-snmp/statSSTP.c @@ -8,18 +8,17 @@ #include <net-snmp/agent/net-snmp-agent-includes.h> #include "triton.h" +#include "accel-pppd/ctrl/sstp/sstp.h" #include "statSSTP.h" -/* - * The variables we want to tie the relevant OIDs to. - * The agent will handle all GET and (if applicable) SET requests - * to these variables automatically, changing the values as needed. - */ - -void sstp_get_stat(unsigned int **, unsigned int **); - -static unsigned int *stat_starting; -static unsigned int *stat_active; +static int handle_statSSTPStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); +static int handle_statSSTPActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests); /* * Our initialization routine, called automatically by the agent @@ -28,9 +27,6 @@ static unsigned int *stat_active; void init_statSSTP(void) { - netsnmp_handler_registration *reg; - netsnmp_watcher_info *winfo; - static oid statSSTPStarting_oid[] = { 1,3,6,1,4,1,8072,100,1,7,1 }; static oid statSSTPActive_oid[] = { 1,3,6,1,4,1,8072,100,1,7,2 }; @@ -43,51 +39,75 @@ init_statSSTP(void) if (!triton_module_loaded("sstp")) return; - sstp_get_stat(&stat_starting, &stat_active); - - /* - * Register scalar watchers for each of the MIB objects. - * The ASN type and RO/RW status are taken from the MIB definition, - * but can be adjusted if needed. - * - * In most circumstances, the scalar watcher will handle all - * of the necessary processing. But the NULL parameter in the - * netsnmp_create_handler_registration() call can be used to - * supply a user-provided handler if necessary. - * - * This approach can also be used to handle Counter64, string- - * and OID-based watched scalars (although variable-sized writeable - * objects will need some more specialised initialisation). - */ DEBUGMSGTL(("statSSTP", "Initializing statSSTPStarting scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statSSTPStarting", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statSSTPStarting", handle_statSSTPStarting, statSSTPStarting_oid, OID_LENGTH(statSSTPStarting_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_starting, sizeof(*stat_starting), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statSSTPStarting" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statSSTPStarting" ); } DEBUGMSGTL(("statSSTP", "Initializing statSSTPActive scalar integer. Default value = %d\n", 0)); - reg = netsnmp_create_handler_registration( - "statSSTPActive", NULL, + if (netsnmp_register_scalar(netsnmp_create_handler_registration( + "statSSTPActive", handle_statSSTPActive, statSSTPActive_oid, OID_LENGTH(statSSTPActive_oid), - HANDLER_CAN_RONLY); - winfo = netsnmp_create_watcher_info( - stat_active, sizeof(*stat_active), - ASN_INTEGER, WATCHER_FIXED_SIZE); - if (netsnmp_register_watched_scalar( reg, winfo ) < 0 ) { - snmp_log( LOG_ERR, "Failed to register watched statSSTPActive" ); + HANDLER_CAN_RONLY)) < 0 ) { + snmp_log( LOG_ERR, "Failed to register statSSTPActive" ); } DEBUGMSGTL(("statSSTP", "Done initalizing statSSTP module\n")); } + +static int handle_statSSTPStarting(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = sstp_stat_starting(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statSSTPStarting\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} + +static int handle_statSSTPActive(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + long stat; + + (void)handler; + (void)reginfo; + + switch (reqinfo->mode) { + case MODE_GET: + stat = sstp_stat_active(); + snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, + (u_char *)&stat, sizeof(stat)); + break; + default: + snmp_log(LOG_ERR, "unknown mode (%d) in handle_statSSTPActive\n", reqinfo->mode); + return SNMP_ERR_GENERR; + } + + return SNMP_ERR_NOERROR; +} diff --git a/accel-pppd/extra/pppd_compat.c b/accel-pppd/extra/pppd_compat.c index 040e7d90..12363cd4 100644 --- a/accel-pppd/extra/pppd_compat.c +++ b/accel-pppd/extra/pppd_compat.c @@ -518,6 +518,10 @@ static void write_radattr(struct pppd_compat_pd *pd, struct rad_packet_t *pack) int fd, i; in_addr_t addr; char ip_str[50]; + union { + uint64_t ifid; + uint16_t u16[4]; + } ifid_u; if (ses->state == AP_STATE_ACTIVE) { sprintf(fname1, "%s.%s", conf_radattr_prefix, ses->ifname); @@ -572,6 +576,10 @@ static void write_radattr(struct pppd_compat_pd *pd, struct rad_packet_t *pack) inet_ntop(AF_INET6, &attr->val.ipv6addr, ip_str, sizeof(ip_str)); fprintf(f, "%s\n", ip_str); break; + case ATTR_TYPE_IFID: + ifid_u.ifid = attr->val.ifid; + fprintf(f, "%x:%x:%x:%x\n", ntohs(ifid_u.u16[0]), ntohs(ifid_u.u16[1]), ntohs(ifid_u.u16[2]), ntohs(ifid_u.u16[3])); + break; } } fclose(f); diff --git a/accel-pppd/ifcfg.c b/accel-pppd/ifcfg.c index 3750060b..4e4a381a 100644 --- a/accel-pppd/ifcfg.c +++ b/accel-pppd/ifcfg.c @@ -234,7 +234,7 @@ void __export ap_session_ifdown(struct ap_session *ses) if (!a->installed) continue; if (a->prefix_len > 64) - ip6route_del(ses->ifindex, &a->addr, a->prefix_len, NULL, 0, 0); + ip6route_del(ses->ifindex, &a->addr, a->prefix_len, NULL, 0, 0, ses->vrf_name); else { struct in6_addr addr; memcpy(addr.s6_addr, &a->addr, 8); diff --git a/accel-pppd/include/ap_session.h b/accel-pppd/include/ap_session.h index 27471859..a4d3b867 100644 --- a/accel-pppd/include/ap_session.h +++ b/accel-pppd/include/ap_session.h @@ -136,10 +136,14 @@ extern int ap_shutdown; extern int sock_fd; extern int sock6_fd; extern int urandom_fd; -extern struct ap_session_stat ap_session_stat; extern int conf_max_sessions; extern int conf_max_starting; +void ap_session_stat_get(struct ap_session_stat *stat); +unsigned int ap_session_stat_starting(void); +unsigned int ap_session_stat_active(void); +unsigned int ap_session_stat_finishing(void); + void ap_session_init(struct ap_session *ses); void ap_session_set_ifindex(struct ap_session *ses); int ap_session_starting(struct ap_session *ses); diff --git a/accel-pppd/ipdb.c b/accel-pppd/ipdb.c index dd8c61c9..8fc08063 100644 --- a/accel-pppd/ipdb.c +++ b/accel-pppd/ipdb.c @@ -83,7 +83,10 @@ void __export build_ip6_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct i if (a->prefix_len <= 64) *(uint64_t *)(addr->s6_addr + 8) = intf_id; else - *(uint64_t *)(addr->s6_addr + 8) |= intf_id & htobe64((1 << (128 - a->prefix_len)) - 1); + /* prefix_len 65..127 means a shift of up to 63 bits: a plain + * int literal 1 is undefined behavior for shifts >= 31, so the + * host bits mask must be built from a 64-bit constant */ + *(uint64_t *)(addr->s6_addr + 8) |= intf_id & htobe64((UINT64_C(1) << (128 - a->prefix_len)) - 1); } diff --git a/accel-pppd/ipv6/dhcpv6.c b/accel-pppd/ipv6/dhcpv6.c index 77fc32f7..b284df5f 100644 --- a/accel-pppd/ipv6/dhcpv6.c +++ b/accel-pppd/ipv6/dhcpv6.c @@ -162,7 +162,7 @@ static void ev_ses_finished(struct ap_session *ses) if (pd->dp_active) { struct ipv6db_addr_t *p; list_for_each_entry(p, &ses->ipv6_dp->prefix_list, entry) - ip6route_del(0, &p->addr, p->prefix_len, NULL, 0, 0); + ip6route_del(0, &p->addr, p->prefix_len, NULL, 0, 0, NULL); } ipdb_put_ipv6_prefix(ses, ses->ipv6_dp); @@ -184,7 +184,7 @@ static void insert_dp_routes(struct ap_session *ses, struct dhcpv6_pd *pd, struc addr = NULL; list_for_each_entry(p, &ses->ipv6_dp->prefix_list, entry) { - if (ip6route_add(ses->ifindex, &p->addr, p->prefix_len, addr, 0, 0)) { + if (ip6route_add(ses->ifindex, &p->addr, p->prefix_len, addr, 0, 0, NULL)) { err = errno; inet_ntop(AF_INET6, &p->addr, str1, sizeof(str1)); if (addr) @@ -752,6 +752,32 @@ static void dhcpv6_recv_rebind(struct dhcpv6_packet *req) dhcpv6_send_reply2(req, pd, D6_REPLY); } +static void dhcpv6_recv_confirm(struct dhcpv6_packet *req) +{ + struct dhcpv6_pd *pd = req->pd; + + if (!req->clientid) { + log_ppp_error("dhcpv6: no Client-ID option\n"); + return; + } + + if (req->serverid) { + log_ppp_error("dhcpv6: unexcpected Server-ID option\n"); + return; + } + + if (!pd->clientid) + return; + else if (pd->clientid->hdr.len != req->clientid->hdr.len || memcmp(pd->clientid, req->clientid, sizeof(struct dhcpv6_opt_hdr) + ntohs(req->clientid->hdr.len))) { + log_ppp_error("dhcpv6: unmatched Client-ID option\n"); + return; + } + + req->serverid = conf_serverid; + + dhcpv6_send_reply(req, pd, D6_REPLY); +} + static void dhcpv6_recv_release(struct dhcpv6_packet *pkt) { // don't answer @@ -783,6 +809,9 @@ static void dhcpv6_recv_packet(struct dhcpv6_packet *pkt) case D6_REBIND: dhcpv6_recv_rebind(pkt); break; + case D6_CONFIRM: + dhcpv6_recv_confirm(pkt); + break; case D6_RELEASE: dhcpv6_recv_release(pkt); break; @@ -841,13 +870,15 @@ static int dhcpv6_read(struct triton_md_handler_t *h) static void add_aftr_gw(const char *val) { - int n = strlen(val); + int n; const char *ptr; uint8_t *buf; - if (!val) + if (!val || !*val) return; + n = strlen(val); + if (val[n - 1] == '.') n++; else @@ -888,13 +919,15 @@ static void add_aftr_gw(const char *val) static void add_dnssl(const char *val) { - int n = strlen(val); + int n; const char *ptr; uint8_t *buf; - if (!val) + if (!val || !*val) return; + n = strlen(val); + if (val[n - 1] == '.') n++; else diff --git a/accel-pppd/ipv6/dhcpv6_packet.c b/accel-pppd/ipv6/dhcpv6_packet.c index 1890bc11..e0f2b5d9 100644 --- a/accel-pppd/ipv6/dhcpv6_packet.c +++ b/accel-pppd/ipv6/dhcpv6_packet.c @@ -551,21 +551,40 @@ static void print_dnssl(struct dhcpv6_option *opt, void (*print)(const char *fmt } -static void print_aftr_gw(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...)) { +static void print_aftr_gw(struct dhcpv6_option *opt, void (*print)(const char *fmt, ...)) +{ int len = ntohs(opt->hdr->len); int offset = 0; - char domain[255]; + int pos = 0; + int done = 0; + char domain[256]; uint8_t label_len; - memset(domain, 0, 255); + memset(domain, 0, sizeof(domain)); while (offset < len) { - label_len = opt->hdr->data[offset]; - if (label_len == 0) + label_len = opt->hdr->data[offset++]; + if (label_len == 0) { + done = 1; break; - memcpy(&domain[offset], &opt->hdr->data[offset + 1], label_len); + } + + if (label_len > 63 || offset + label_len > len || + pos + label_len + 1 >= sizeof(domain)) { + print(" <invalid>"); + return; + } + + memcpy(&domain[pos], &opt->hdr->data[offset], label_len); offset += label_len; - domain[offset++] = '.'; + pos += label_len; + domain[pos++] = '.'; } + + if (!done || offset != len) { + print(" <invalid>"); + return; + } + print(" %s", domain); } @@ -577,4 +596,3 @@ static void print_ia_prefix(struct dhcpv6_option *opt, void (*print)(const char inet_ntop(AF_INET6, &o->prefix, str, sizeof(str)); print(" %s/%i pref_lifetime=%i valid_lifetime=%i", str, o->prefix_len, ntohl(o->pref_lifetime), ntohl(o->valid_lifetime)); } - diff --git a/accel-pppd/ipv6/nd.c b/accel-pppd/ipv6/nd.c index 297e4d63..6dd00ee2 100644 --- a/accel-pppd/ipv6/nd.c +++ b/accel-pppd/ipv6/nd.c @@ -412,13 +412,15 @@ static void ev_ses_finishing(struct ap_session *ses) static void add_dnssl(const char *val) { - int n = strlen(val); + int n; const char *ptr; uint8_t *buf; - if (!val) + if (!val || !*val) return; + n = strlen(val); + if (val[n - 1] == '.') n++; else diff --git a/accel-pppd/libnetlink/iputils.c b/accel-pppd/libnetlink/iputils.c index 23325fcd..a5e3bc51 100644 --- a/accel-pppd/libnetlink/iputils.c +++ b/accel-pppd/libnetlink/iputils.c @@ -11,10 +11,13 @@ #include <errno.h> #include <time.h> #include <sys/uio.h> -//#include <linux/if_link.h> +#ifdef HAVE_VRF +#include <linux/if_link.h> +#endif //#include <linux/if_addr.h> //#include <linux/rtnetlink.h> #include <linux/fib_rules.h> +#include <net/if.h> #include "log.h" @@ -213,7 +216,8 @@ int __export iplink_vlan_add(const char *ifname, int ifindex, int vid) data = NLMSG_TAIL(&req.n); addattr_l(&req.n, 4096, IFLA_INFO_DATA, NULL, 0); - addattr_l(&req.n, 4096, IFLA_VLAN_ID, &vid, 2); + uint16_t vid_16b = (uint16_t)vid; + addattr_l(&req.n, 4096, IFLA_VLAN_ID, &vid_16b, 2); data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; @@ -457,7 +461,89 @@ int __export ipaddr_del_peer(int ifindex, in_addr_t addr, in_addr_t peer) return r; } -int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio) +#ifdef HAVE_VRF +static int ipvrf_get_table(uint32_t *tb_id, const char *vrf_name) +{ + struct iplink_req { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[4096]; + } req; + struct rtattr *tb[IFLA_MAX+1]; + struct rtattr *li[IFLA_INFO_MAX+1]; + struct rtattr *vrf_attr[IFLA_VRF_MAX + 1]; + struct ifinfomsg *ifi; + struct rtnl_handle *rth; + int len; + int r = -1; + *tb_id = RT_TABLE_MAIN; + + if (!vrf_name) + return 0; + + log_ppp_info2("utils: getting route table for %s\n", vrf_name); + + rth = net->rtnl_get(); + if (!rth) + return -1; + + memset(&req, 0, sizeof(req) - 4096); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_GETLINK; + req.i.ifi_family = AF_UNSPEC; + + addattr_l(&req.n, 4096, IFLA_IFNAME, vrf_name, strnlen(vrf_name, IFNAMSIZ)); + + r = rtnl_talk(rth, &req.n, 0, 0, &req.n, NULL, NULL, 0); + if (r < 0) { + log_ppp_error("BUG: route table \"%s\" not found\n", vrf_name); + goto out; + } + + ifi = NLMSG_DATA(&req.n); + + len = req.n.nlmsg_len; + + len -= NLMSG_LENGTH(sizeof(*ifi)); + if (len < 0) { + goto error; + } + + parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); + + if (!tb[IFLA_LINKINFO]) + goto error; + + parse_rtattr_nested(li, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); + + if (!li[IFLA_INFO_KIND] || !li[IFLA_INFO_DATA]) + goto error; + + if (strncmp(RTA_DATA(li[IFLA_INFO_KIND]), "vrf", 4)) { + log_ppp_error("BUG: link \"%s\" is not VRF\n", vrf_name); + goto error; + } + + parse_rtattr_nested(vrf_attr, IFLA_VRF_MAX, li[IFLA_INFO_DATA]); + if (vrf_attr[IFLA_VRF_TABLE]) + *tb_id = *(uint32_t *)RTA_DATA(vrf_attr[IFLA_VRF_TABLE]); + + if (*tb_id == 0) + log_ppp_error("BUG: VRF %s is missing table id\n", vrf_name); + + r = 0; + goto out; +error: + r = -1; +out: + net->rtnl_put(rth); + return r; +} +#endif + +int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio, const char *vrf_name) { struct ipaddr_req { struct nlmsghdr n; @@ -472,16 +558,26 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw memset(&req, 0, sizeof(req) - 4096); + uint32_t rt_table = RT_TABLE_MAIN; +#ifdef HAVE_VRF + if (ipvrf_get_table(&rt_table, vrf_name) < 0) { + r = -1; + goto out; + } +#endif + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; req.n.nlmsg_type = RTM_NEWROUTE; req.i.rtm_family = AF_INET; - req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_table = rt_table; req.i.rtm_scope = gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = mask; + if (rt_table != RT_TABLE_MAIN) + addattr32(&req.n, sizeof(req), RTA_TABLE, rt_table); if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); if (src) @@ -495,12 +591,13 @@ int __export iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) r = -1; +out: net->rtnl_put(rth); return r; } -int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio) +int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio, const char *vrf_name) { struct ipaddr_req { struct nlmsghdr n; @@ -515,16 +612,26 @@ int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw memset(&req, 0, sizeof(req) - 4096); + uint32_t rt_table = RT_TABLE_MAIN; +#ifdef HAVE_VRF + if (ipvrf_get_table(&rt_table, vrf_name) < 0) { + r = -1; + goto out; + } +#endif + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELROUTE; req.i.rtm_family = AF_INET; - req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_table = rt_table; req.i.rtm_scope = gw ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = mask; + if (rt_table != RT_TABLE_MAIN) + addattr32(&req.n, sizeof(req), RTA_TABLE, rt_table); if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); if (src) @@ -538,12 +645,13 @@ int __export iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) r = -1; +out: net->rtnl_put(rth); return r; } -int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio) +int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio, const char *vrf_name) { struct ipaddr_req { struct nlmsghdr n; @@ -558,17 +666,27 @@ int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, memset(&req, 0, sizeof(req) - 4096); + uint32_t rt_table = RT_TABLE_MAIN; +#ifdef HAVE_VRF + if (ipvrf_get_table(&rt_table, vrf_name) < 0) { + r = -1; + goto out; + } +#endif + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE; req.n.nlmsg_type = RTM_NEWROUTE; req.i.rtm_family = AF_INET6; - req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_table = rt_table; req.i.rtm_scope = RT_SCOPE_UNIVERSE; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = pref_len; addattr_l(&req.n, sizeof(req), RTA_DST, dst, sizeof(*dst)); + if (rt_table != RT_TABLE_MAIN) + addattr32(&req.n, sizeof(req), RTA_TABLE, rt_table); if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); if (gw) @@ -579,12 +697,13 @@ int __export ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) r = -1; +out: net->rtnl_put(rth); return r; } -int __export ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio) +int __export ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio, const char *vrf_name) { struct ipaddr_req { struct nlmsghdr n; @@ -599,17 +718,27 @@ int __export ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, memset(&req, 0, sizeof(req) - 4096); + uint32_t rt_table = RT_TABLE_MAIN; +#ifdef HAVE_VRF + if (ipvrf_get_table(&rt_table, vrf_name) < 0) { + r = -1; + goto out; + } +#endif + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELROUTE; req.i.rtm_family = AF_INET6; - req.i.rtm_table = RT_TABLE_MAIN; + req.i.rtm_table = rt_table; req.i.rtm_scope = RT_SCOPE_UNIVERSE; req.i.rtm_protocol = proto; req.i.rtm_type = RTN_UNICAST; req.i.rtm_dst_len = pref_len; addattr_l(&req.n, sizeof(req), RTA_DST, dst, sizeof(*dst)); + if (rt_table != RT_TABLE_MAIN) + addattr32(&req.n, sizeof(req), RTA_TABLE, rt_table); if (ifindex) addattr32(&req.n, sizeof(req), RTA_OIF, ifindex); if (gw) @@ -620,6 +749,7 @@ int __export ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0) r = -1; +out: net->rtnl_put(rth); return r; diff --git a/accel-pppd/libnetlink/iputils.h b/accel-pppd/libnetlink/iputils.h index 9292cea2..86500882 100644 --- a/accel-pppd/libnetlink/iputils.h +++ b/accel-pppd/libnetlink/iputils.h @@ -4,6 +4,7 @@ #include <linux/if_link.h> #include <netinet/in.h> #include <stdint.h> +#include <config.h> typedef int (*iplink_list_func)(int index, int flags, const char *name, int iflink, int vid, void *arg); @@ -20,12 +21,12 @@ int ipaddr_add_peer(int ifindex, in_addr_t addr, in_addr_t peer_addr); int ipaddr_del(int ifindex, in_addr_t addr, int mask); int ipaddr_del_peer(int ifindex, in_addr_t addr, in_addr_t peer); -int iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio); -int iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio); +int iproute_add(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio, const char *vrf_name); +int iproute_del(int ifindex, in_addr_t src, in_addr_t dst, in_addr_t gw, int proto, int mask, uint32_t prio, const char *vrf_name); in_addr_t iproute_get(in_addr_t dst, in_addr_t *gw); -int ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio); -int ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio); +int ip6route_add(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio, const char *vrf_name); +int ip6route_del(int ifindex, const struct in6_addr *dst, int pref_len, const struct in6_addr *gw, int proto, uint32_t prio, const char *vrf_name); int ip6addr_add(int ifindex, struct in6_addr *addr, int prefix_len); int ip6addr_add_peer(int ifindex, struct in6_addr *addr, struct in6_addr *peer_addr); int ip6addr_del(int ifindex, struct in6_addr *addr, int prefix_len); diff --git a/accel-pppd/logs/log_file.c b/accel-pppd/logs/log_file.c index 481afa1e..26dd4422 100644 --- a/accel-pppd/logs/log_file.c +++ b/accel-pppd/logs/log_file.c @@ -385,7 +385,12 @@ static void general_reopen(void) { const char *fname = conf_get_opt("log", "log-file"); int old_fd = -1; - int fd = open(fname, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, S_IRUSR | S_IWUSR); + int fd; + + if (!fname) + return; + + fd = open(fname, O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, S_IRUSR | S_IWUSR); if (fd < 0) { log_emerg("log_file: open '%s': %s\n", fname, strerror(errno)); return; @@ -422,7 +427,7 @@ static void free_lpd(struct log_file_pd_t *lpd) if (lpd->lf.fd != -1) close(lpd->lf.fd); if (lpd->lf.new_fd != -1) - close(lpd->lf.fd); + close(lpd->lf.new_fd); spin_unlock(&lpd->lf.lock); mempool_free(lpd); } @@ -710,7 +715,8 @@ static void init(void) if (opt && atoi(opt) > 0) conf_copy = 1; - log_register_target(&general_target); + if (log_file) + log_register_target(&general_target); if (conf_per_user_dir) { log_register_target(&per_user_target); diff --git a/accel-pppd/logs/log_tcp.c b/accel-pppd/logs/log_tcp.c index e0663d34..ca803a7e 100644 --- a/accel-pppd/logs/log_tcp.c +++ b/accel-pppd/logs/log_tcp.c @@ -163,7 +163,7 @@ static int log_tcp_connect(struct triton_md_handler_t *h) { struct tcp_target_t *t = container_of(h, typeof(*t), hnd); - if (connect(t->hnd.fd, &t->addr, sizeof(t->addr))) { + if (connect(t->hnd.fd, (struct sockaddr*)&t->addr, sizeof(t->addr))) { if (errno == EAGAIN) return 0; if (errno == EINPROGRESS) @@ -216,7 +216,7 @@ static void start_connect(struct tcp_target_t *t) return; } - if (connect(t->hnd.fd, &t->addr, sizeof(t->addr))) { + if (connect(t->hnd.fd, (struct sockaddr*)&t->addr, sizeof(t->addr))) { if (errno != EINPROGRESS) { log_emerg("log-tcp: connect: %s\n", strerror(errno)); close(t->hnd.fd); diff --git a/accel-pppd/main.c b/accel-pppd/main.c index bbc36d95..221be7be 100644 --- a/accel-pppd/main.c +++ b/accel-pppd/main.c @@ -16,9 +16,7 @@ #include <sys/wait.h> #include <sys/resource.h> -#ifdef CRYPTO_OPENSSL #include <openssl/ssl.h> -#endif #include "triton/triton.h" @@ -43,7 +41,8 @@ static int term; static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; -#ifdef CRYPTO_OPENSSL +static volatile sig_atomic_t need_reload; + #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) static pthread_mutex_t *ssl_lock_cs; @@ -76,16 +75,14 @@ static void ssl_lock_init(void) static void openssl_init(void) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); OpenSSL_add_all_digests(); - -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) ssl_lock_init(); #endif } -#endif static void change_limits(void) { @@ -105,7 +102,7 @@ static void change_limits(void) log_emerg("main: setrlimit: %s\n", strerror(errno)); } -static void config_reload_notify(int r) +static void config_reload_notify(int r, void *arg) { if (!r) triton_event_fire(EV_CONFIG_RELOAD, NULL); @@ -113,7 +110,7 @@ static void config_reload_notify(int r) static void config_reload(int num) { - triton_conf_reload(config_reload_notify); + need_reload = 1; } static void close_all_fd(void) @@ -393,9 +390,7 @@ int main(int _argc, char **_argv) change_limits(); -#ifdef CRYPTO_OPENSSL openssl_init(); -#endif triton_register_init(0, log_version); @@ -444,7 +439,19 @@ int main(int _argc, char **_argv) backup_restore(internal); #endif - sigwait(&set, &sig); + { + struct timespec ts = { .tv_sec = 1 }; + while (1) { + sig = sigtimedwait(&set, NULL, &ts); + if (sig > 0) + break; + if (need_reload) { + need_reload = 0; + if (triton_conf_reload(config_reload_notify, NULL)) + log_warn("main: config reload is already in progress\n"); + } + } + } log_info1("terminate, sig = %i\n", sig); ap_shutdown_soft(shutdown_cb, 1); diff --git a/accel-pppd/ppp/ipv6cp_opt_intfid.c b/accel-pppd/ppp/ipv6cp_opt_intfid.c index fff74160..cb33f024 100644 --- a/accel-pppd/ppp/ipv6cp_opt_intfid.c +++ b/accel-pppd/ppp/ipv6cp_opt_intfid.c @@ -1,6 +1,7 @@ #include <stdlib.h> #include <stdio.h> #include <unistd.h> +#include <endian.h> #include <fcntl.h> #include <string.h> #include <errno.h> @@ -25,9 +26,16 @@ static int conf_check_exists; static int conf_intf_id = INTF_ID_FIXED; -static uint64_t conf_intf_id_val = 1; +/* Fixed intf-id values are stored in network byte order: the rest of + * the code (build_ip6_addr(), ifcfg.c, nd.c, ...) copies them into the + * low 8 bytes of the IPv6 address as-is, and parse_intfid() already + * produces network byte order. The old host-order defaults (1 and 2) + * therefore yielded ::100:0:0:0 / ::200:0:0:0 instead of ::1 / ::2 on + * little-endian hosts. Defaults are assigned in init() because + * htobe64() is not a constant expression on all libcs (e.g. musl). */ +static uint64_t conf_intf_id_val; static int conf_peer_intf_id = INTF_ID_FIXED; -static uint64_t conf_peer_intf_id_val = 2; +static uint64_t conf_peer_intf_id_val; static int conf_accept_peer_intf_id; static struct ipv6cp_option_t *ipaddr_init(struct ppp_ipv6cp_t *ipv6cp); @@ -354,6 +362,11 @@ static void load_config(void) static void init() { + /* network byte order, so the resulting addresses are ::1 and ::2 + * regardless of host endianness */ + conf_intf_id_val = htobe64(1); + conf_peer_intf_id_val = htobe64(2); + if (sock6_fd < 0) return; diff --git a/accel-pppd/ppp/ppp.c b/accel-pppd/ppp/ppp.c index 8a4cce7c..cd726e17 100644 --- a/accel-pppd/ppp/ppp.c +++ b/accel-pppd/ppp/ppp.c @@ -12,8 +12,6 @@ #include <sys/ioctl.h> #include "linux_ppp.h" -#include "crypto.h" - #include "triton.h" #include "ap_session.h" @@ -59,7 +57,7 @@ static mempool_t uc_pool; static int ppp_chan_read(struct triton_md_handler_t*); static int ppp_unit_read(struct triton_md_handler_t*); -static void init_layers(struct ppp_t *); +static int init_layers(struct ppp_t *); static void _free_layers(struct ppp_t *); static void start_first_layer(struct ppp_t *); static int setup_ppp_mru(struct ppp_t *ppp); @@ -103,7 +101,8 @@ int __export establish_ppp(struct ppp_t *ppp) goto exit_close_chan; } - init_layers(ppp); + if (init_layers(ppp)) + goto exit_close_chan; if (list_empty(&ppp->layers)) { log_ppp_error("no layers to start\n"); goto exit_close_chan; @@ -145,15 +144,13 @@ int __export connect_ppp_channel(struct ppp_t *ppp) return 0; } - if (uc_size) { - pthread_mutex_lock(&uc_lock); - if (!list_empty(&uc_list)) { - uc = list_entry(uc_list.next, typeof(*uc), entry); - list_del(&uc->entry); - --uc_size; - } - pthread_mutex_unlock(&uc_lock); + pthread_mutex_lock(&uc_lock); + if (!list_empty(&uc_list)) { + uc = list_entry(uc_list.next, typeof(*uc), entry); + list_del(&uc->entry); + --uc_size; } + pthread_mutex_unlock(&uc_lock); if (uc) { ppp->unit_fd = uc->fd; @@ -272,10 +269,11 @@ static void destablish_ppp(struct ppp_t *ppp) if (conf_unit_cache) { struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); if (ppp->ses.net != def_net) { if (net->move_link(def_net, ppp->ses.ifindex)) { log_ppp_warn("failed to attach to default namespace\n"); - triton_md_unregister_handler(&ppp->unit_hnd, 1); + triton_md_unregister_handler(&ppp->unit_hnd, 0); goto skip; } ppp->ses.net = def_net; @@ -288,7 +286,7 @@ static void destablish_ppp(struct ppp_t *ppp) strncpy(ifr.ifr_name, ppp->ses.ifname, IFNAMSIZ); if (net->sock_ioctl(SIOCSIFNAME, &ifr)) { log_ppp_warn("failed to rename ppp to default name\n"); - triton_md_unregister_handler(&ppp->unit_hnd, 1); + triton_md_unregister_handler(&ppp->unit_hnd, 0); goto skip; } } @@ -301,11 +299,18 @@ static void destablish_ppp(struct ppp_t *ppp) uc->fd = ppp->unit_fd; uc->unit_idx = ppp->ses.unit_idx; } else - triton_md_unregister_handler(&ppp->unit_hnd, 1); + triton_md_unregister_handler(&ppp->unit_hnd, 0); skip: ap_session_finished(&ppp->ses); + /* The unit fd is closed only after session cleanup (ip-down scripts, + * radattr removal) has finished, so the kernel cannot give the same + * unit index (and thus ifname) to a new session while cleanup still + * references the ifname. */ + if (!uc) + close(ppp->unit_fd); + ppp->unit_fd = -1; destroy_ppp_channel(ppp); @@ -673,7 +678,7 @@ void __export ppp_unregister_layer(struct ppp_layer_t *layer) list_del(&layer->entry); } -static void init_layers(struct ppp_t *ppp) +static int init_layers(struct ppp_t *ppp) { struct layer_node_t *n, *n1; struct ppp_layer_t *l; @@ -686,12 +691,18 @@ static void init_layers(struct ppp_t *ppp) list_add_tail(&n1->entry, &ppp->layers); list_for_each_entry(l, &n->items, entry) { d = l->init(ppp); + if (!d) { + log_ppp_error("ppp layer init failed\n"); + _free_layers(ppp); + return -1; + } d->layer = l; d->started = 0; d->node = n1; list_add_tail(&d->entry, &n1->items); } } + return 0; } static void _free_layers(struct ppp_t *ppp) diff --git a/accel-pppd/ppp/ppp_ipv6cp.c b/accel-pppd/ppp/ppp_ipv6cp.c index 1194b314..7f278daa 100644 --- a/accel-pppd/ppp/ppp_ipv6cp.c +++ b/accel-pppd/ppp/ppp_ipv6cp.c @@ -205,8 +205,12 @@ static void ipv6cp_layer_finished(struct ppp_fsm_t *fsm) ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_ERROR, 0); else ppp_layer_passive(ipv6cp->ppp, &ipv6cp->ld); - } else if (!ipv6cp->ppp->ses.terminating) - ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_ERROR, 0); + } else if (!ipv6cp->ppp->ses.terminating) { + if (conf_ipv6 == IPV6_REQUIRE) + ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_ERROR, 0); + else + log_ppp_info1("ipv6cp: closed, session continues without IPv6\n"); + } fsm->fsm_state = FSM_Closed; } @@ -738,7 +742,12 @@ static void ipv6cp_recv(struct ppp_handler_t*h) if (conf_ppp_verbose) log_ppp_info2("recv [IPV6CP TermReq id=%x]\n", hdr->id); ppp_fsm_recv_term_req(&ipv6cp->fsm); - ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_REQUEST, 0); + /* RFC 1661 sec 3.7: closing one NCP is not sufficient reason + * to terminate the PPP link */ + if (conf_ipv6 == IPV6_REQUIRE) + ap_session_terminate(&ipv6cp->ppp->ses, TERM_USER_REQUEST, 0); + else + ppp_layer_passive(ipv6cp->ppp, &ipv6cp->ld); break; case TERMACK: if (conf_ppp_verbose) diff --git a/accel-pppd/ppp/ppp_lcp.c b/accel-pppd/ppp/ppp_lcp.c index 10babec8..05b6c4a6 100644 --- a/accel-pppd/ppp/ppp_lcp.c +++ b/accel-pppd/ppp/ppp_lcp.c @@ -16,6 +16,10 @@ #include "memdebug.h" +#ifndef min +#define min(x,y) ((x)<(y)?(x):(y)) +#endif + struct recv_opt_t { struct list_head entry; @@ -610,12 +614,13 @@ static void send_echo_reply(struct ppp_lcp_t *lcp) lcp->last_echo_ts = _time(); hdr->code = ECHOREP; - *(uint32_t *)(hdr + 1) = htonl(lcp->magic); + uint32_t magic = htonl(lcp->magic); + memcpy((char *)hdr + sizeof(struct lcp_hdr_t), &magic, sizeof(magic)); if (conf_ppp_verbose) log_ppp_debug("send [LCP EchoRep id=%x <magic %08x>]\n", hdr->id, lcp->magic); - ppp_chan_send(lcp->ppp, hdr, ntohs(hdr->len) + 2); + ppp_chan_send(lcp->ppp, hdr, min(ntohs(hdr->len), lcp->ppp->mtu) + 2); } static void send_echo_request(struct triton_timer_t *t) @@ -733,6 +738,8 @@ static void lcp_recv(struct ppp_handler_t*h) struct ppp_lcp_t *lcp = container_of(h, typeof(*lcp), hnd); int r; char *term_msg; + uint16_t len; + int buf_len; if (lcp->ppp->buf_size < PPP_HEADERLEN + 2) { log_ppp_warn("LCP: short packet received\n"); @@ -740,7 +747,9 @@ static void lcp_recv(struct ppp_handler_t*h) } hdr = (struct lcp_hdr_t *)lcp->ppp->buf; - if (ntohs(hdr->len) < PPP_HEADERLEN) { + len = ntohs(hdr->len); + buf_len = lcp->ppp->buf_size; + if (len < PPP_HEADERLEN) { log_ppp_warn("LCP: short packet received\n"); return; } @@ -827,25 +836,53 @@ static void lcp_recv(struct ppp_handler_t*h) ppp_fsm_recv_code_rej_bad(&lcp->fsm); break; case ECHOREQ: + if (len < PPP_HDRLEN + 4 || buf_len < (int)(sizeof(*hdr) + 4)) { + log_ppp_warn("LCP: short EchoReq received\n"); + break; + } if (conf_ppp_verbose) log_ppp_debug("recv [LCP EchoReq id=%x <magic %08x>]\n", hdr->id, ntohl(*(uint32_t*)(hdr + 1))); send_echo_reply(lcp); break; case ECHOREP: + if (len < PPP_HDRLEN + 4 || buf_len < (int)(sizeof(*hdr) + 4)) { + log_ppp_warn("LCP: short EchoRep received\n"); + break; + } lcp_recv_echo_repl(lcp, (uint8_t*)(hdr + 1), ntohs(hdr->len) - PPP_HDRLEN); break; case PROTOREJ: - if (conf_ppp_verbose) + if (conf_ppp_verbose) { + if (len < PPP_HDRLEN + 2 || buf_len < (int)(sizeof(*hdr) + 2)) { + log_ppp_warn("LCP: short ProtoRej received\n"); + break; + } log_ppp_info2("recv [LCP ProtoRej id=%x <%04x>]\n", hdr->id, ntohs(*(uint16_t*)(hdr + 1))); + } + if (len < PPP_HDRLEN + 2 || buf_len < (int)(sizeof(*hdr) + 2)) + break; ppp_recv_proto_rej(lcp->ppp, ntohs(*(uint16_t *)(hdr + 1))); break; case DISCARDREQ: - if (conf_ppp_verbose) + if (conf_ppp_verbose) { + if (len < PPP_HDRLEN + 4 || buf_len < (int)(sizeof(*hdr) + 4)) { + log_ppp_warn("LCP: short DiscardReq received\n"); + break; + } log_ppp_info2("recv [LCP DiscardReq id=%x <magic %08x>]\n", hdr->id, ntohl(*(uint32_t*)(hdr + 1))); + } break; case IDENT: if (conf_ppp_verbose) { - term_msg = _strndup((char*)(hdr + 1) + 4, ntohs(hdr->len) - 4 - 4); + int id_len; + if (len < PPP_HDRLEN + 4 || buf_len < (int)(sizeof(*hdr) + 4)) { + log_ppp_warn("LCP: short Ident received\n"); + break; + } + id_len = len - PPP_HDRLEN - 4; + if (buf_len < (int)(sizeof(*hdr) + 4 + id_len)) + id_len = buf_len - sizeof(*hdr) - 4; + term_msg = _strndup((char*)(hdr + 1) + 4, id_len); log_ppp_info2("recv [LCP Ident id=%x <%s>]\n", hdr->id, term_msg); _free(term_msg); } diff --git a/accel-pppd/radius/CMakeLists.txt b/accel-pppd/radius/CMakeLists.txt index a0c0d534..3ce72648 100644 --- a/accel-pppd/radius/CMakeLists.txt +++ b/accel-pppd/radius/CMakeLists.txt @@ -22,6 +22,7 @@ ENDIF () ADD_DEFINITIONS(-DDICTIONARY="${CMAKE_INSTALL_PREFIX}/share/accel-ppp/radius/dictionary") ADD_LIBRARY(radius SHARED ${sources}) +TARGET_LINK_LIBRARIES(radius ${crypto_lib}) set_property(TARGET radius PROPERTY CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set_property(TARGET radius PROPERTY INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}/accel-ppp) diff --git a/accel-pppd/radius/acct.c b/accel-pppd/radius/acct.c index 1cbd9296..d30aae7a 100644 --- a/accel-pppd/radius/acct.c +++ b/accel-pppd/radius/acct.c @@ -5,9 +5,10 @@ #include <unistd.h> #include <sys/ioctl.h> #include <netinet/in.h> -#include "linux_ppp.h" -#include "crypto.h" +#include <openssl/md5.h> + +#include "linux_ppp.h" #include "log.h" #include "backup.h" @@ -24,24 +25,32 @@ #define INTERIM_SAFE_TIME 10 -static int req_set_RA(struct rad_req_t *req, const char *secret) +static int req_set_RA(struct rad_req_t *req) { + char *secret; MD5_CTX ctx; - if (rad_packet_build(req->pack, req->RA)) + secret = rad_server_secret_dup(req->serv); + if (!secret) return -1; + if (rad_packet_build(req->pack, req->RA)) { + _free(secret); + return -1; + } + MD5_Init(&ctx); MD5_Update(&ctx, req->pack->buf, req->pack->len); MD5_Update(&ctx, secret, strlen(secret)); MD5_Final(req->pack->buf + 4, &ctx); + _free(secret); + return 0; } static int req_set_stat(struct rad_req_t *req, struct ap_session *ses) { - struct rtnl_link_stats64 stats; struct timespec ts; int ret = 0; @@ -50,15 +59,15 @@ static int req_set_stat(struct rad_req_t *req, struct ap_session *ses) else clock_gettime(CLOCK_MONOTONIC, &ts); - if (ap_session_read_stats(ses, &stats) == 0) { - rad_packet_change_int(req->pack, NULL, "Acct-Input-Octets", (int) (stats.rx_bytes & UINT32_MAX)); - rad_packet_change_int(req->pack, NULL, "Acct-Output-Octets", (int) (stats.tx_bytes & UINT32_MAX)); - rad_packet_change_int(req->pack, NULL, "Acct-Input-Packets", (int) (stats.rx_packets & UINT32_MAX)); - rad_packet_change_int(req->pack, NULL, "Acct-Output-Packets", (int) (stats.tx_packets & UINT32_MAX)); - rad_packet_change_int(req->pack, NULL, "Acct-Input-Gigawords", (int) (stats.rx_bytes >> (sizeof(uint32_t) * 8))); - rad_packet_change_int(req->pack, NULL, "Acct-Output-Gigawords", (int) (stats.tx_bytes >> (sizeof(uint32_t) * 8))); - } else - ret = -1; + if (!ses->terminating) + ret = ap_session_read_stats(ses, NULL); + + rad_packet_change_int(req->pack, NULL, "Acct-Input-Octets", (int) (ses->acct_rx_bytes & UINT32_MAX)); + rad_packet_change_int(req->pack, NULL, "Acct-Output-Octets", (int) (ses->acct_tx_bytes & UINT32_MAX)); + rad_packet_change_int(req->pack, NULL, "Acct-Input-Packets", (int) (ses->acct_rx_packets & UINT32_MAX)); + rad_packet_change_int(req->pack, NULL, "Acct-Output-Packets", (int) (ses->acct_tx_packets & UINT32_MAX)); + rad_packet_change_int(req->pack, NULL, "Acct-Input-Gigawords", (int) (ses->acct_rx_bytes >> (sizeof(uint32_t) * 8))); + rad_packet_change_int(req->pack, NULL, "Acct-Output-Gigawords", (int) (ses->acct_tx_bytes >> (sizeof(uint32_t) * 8))); rad_packet_change_int(req->pack, NULL, "Acct-Session-Time", ts.tv_sec - ses->start_time); @@ -70,7 +79,7 @@ static void rad_acct_sent(struct rad_req_t *req, int res) if (res) return; - __sync_add_and_fetch(&req->serv->stat_interim_sent, 1); + rad_server_stat_interim_sent(req->serv); if (!req->hnd.tpd) triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); @@ -88,8 +97,7 @@ static void rad_acct_recv(struct rad_req_t *req) int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; - stat_accm_add(req->serv->stat_interim_query_1m, dt); - stat_accm_add(req->serv->stat_interim_query_5m, dt); + rad_server_stat_interim_query(req->serv, dt); if (req->timeout.tpd) triton_timer_del(&req->timeout); @@ -109,9 +117,7 @@ static void rad_acct_timeout(struct triton_timer_t *t) rad_server_req_exit(req); rad_server_timeout(req->serv); - __sync_add_and_fetch(&req->serv->stat_interim_lost, 1); - stat_accm_add(req->serv->stat_interim_lost_1m, 1); - stat_accm_add(req->serv->stat_interim_lost_5m, 1); + rad_server_stat_interim_lost(req->serv); if (conf_acct_timeout == 0) { triton_timer_del(t); @@ -183,7 +189,7 @@ static void rad_acct_interim_update(struct triton_timer_t *t) rpd->acct_req->pack->id++; if (!rpd->acct_req->before_send) - req_set_RA(rpd->acct_req, rpd->acct_req->serv->secret); + req_set_RA(rpd->acct_req); rpd->acct_req->timeout.expire_tv.tv_sec = conf_timeout; rpd->acct_req->try = 0; @@ -215,7 +221,7 @@ static int rad_acct_before_send(struct rad_req_t *req) clock_gettime(CLOCK_MONOTONIC, &ts); rad_packet_change_int(req->pack, NULL, "Acct-Delay-Time", ts.tv_sec - req->ts + conf_acct_delay_start); - req_set_RA(req, req->serv->secret); + req_set_RA(req); return 0; } @@ -227,7 +233,7 @@ static void rad_acct_start_sent(struct rad_req_t *req, int res) return; } - __sync_add_and_fetch(&req->serv->stat_acct_sent, 1); + rad_server_stat_acct_sent(req->serv); if (!req->hnd.tpd) triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); @@ -246,8 +252,7 @@ static void rad_acct_start_recv(struct rad_req_t *req) int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; - stat_accm_add(req->serv->stat_acct_query_1m, dt); - stat_accm_add(req->serv->stat_acct_query_5m, dt); + rad_server_stat_acct_query(req->serv, dt); triton_timer_del(&req->timeout); @@ -289,9 +294,7 @@ static void rad_acct_start_timeout(struct triton_timer_t *t) rad_server_timeout(req->serv); - __sync_add_and_fetch(&req->serv->stat_acct_lost, 1); - stat_accm_add(req->serv->stat_acct_lost_1m, 1); - stat_accm_add(req->serv->stat_acct_lost_5m, 1); + rad_server_stat_acct_lost(req->serv); if (req->before_send) req->pack->id++; @@ -314,7 +317,7 @@ static int __rad_acct_start(struct radius_pd_t *rpd) if (conf_acct_delay_time) req->before_send = rad_acct_before_send; - else if (req_set_RA(req, req->serv->secret)) + else if (req_set_RA(req)) goto out_err; req->recv = rad_acct_start_recv; @@ -370,11 +373,21 @@ static void rad_acct_stop_sent(struct rad_req_t *req, int res) rpd->acct_req = NULL; } else if (req->rpd) rad_acct_stop_defer(req->rpd); + else { + /* deferred request: the timeout timer is one-shot and + * nobody else references this request, re-arm it to + * retry later, otherwise the request and its socket + * leak */ + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(NULL, &req->timeout, 0); + } return; } - __sync_add_and_fetch(&req->serv->stat_acct_sent, 1); + rad_server_stat_acct_sent(req->serv); if (!req->hnd.tpd) triton_md_register_handler(req->rpd ? req->rpd->ses->ctrl->ctx : NULL, &req->hnd); @@ -393,8 +406,7 @@ static void rad_acct_stop_recv(struct rad_req_t *req) int dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; - stat_accm_add(req->serv->stat_acct_query_1m, dt); - stat_accm_add(req->serv->stat_acct_query_5m, dt); + rad_server_stat_acct_query(req->serv, dt); rad_req_free(req); @@ -415,25 +427,34 @@ static void rad_acct_stop_timeout(struct triton_timer_t *t) rad_server_timeout(req->serv); rad_server_req_exit(req); - __sync_add_and_fetch(&req->serv->stat_acct_lost, 1); - stat_accm_add(req->serv->stat_acct_lost_1m, 1); - stat_accm_add(req->serv->stat_acct_lost_5m, 1); + rad_server_stat_acct_lost(req->serv); if (req->before_send) req->pack->id++; } - if (req->try == conf_max_try) { + if (req->try >= conf_max_try) { + if (req->rpd) + req->rpd->acct_req = NULL; rad_req_free(req); return; } if (rad_req_send(req)) { if (ap_shutdown) { + if (req->rpd) + req->rpd->acct_req = NULL; rad_req_free(req); return; } - req->try = 0; + /* no server available at the moment; the timeout timer is + * one-shot, re-arm it to retry later, otherwise the request + * and its socket leak; failed attempts count towards + * conf_max_try so the request is freed above eventually */ + if (req->timeout.tpd) + triton_timer_mod(&req->timeout, 0); + else + triton_timer_add(req->rpd ? req->rpd->ses->ctrl->ctx : NULL, &req->timeout, 0); } } @@ -529,10 +550,10 @@ int rad_acct_stop(struct radius_pd_t *rpd) rad_packet_change_val(req->pack, NULL, "Acct-Status-Type", "Stop"); req_set_stat(req, rpd->ses); - req_set_RA(req, req->serv->secret); + req_set_RA(req); req->recv = rad_acct_stop_recv; - req->timeout.expire = rad_acct_start_timeout; + req->timeout.expire = rad_acct_stop_timeout; req->timeout.expire_tv.tv_sec = conf_timeout; req->sent = rad_acct_stop_sent; req->log = conf_verbose ? log_ppp_info1 : NULL; @@ -544,4 +565,3 @@ int rad_acct_stop(struct radius_pd_t *rpd) return 0; } - diff --git a/accel-pppd/radius/auth.c b/accel-pppd/radius/auth.c index 05058547..d2cb9803 100644 --- a/accel-pppd/radius/auth.c +++ b/accel-pppd/radius/auth.c @@ -1,7 +1,8 @@ #include <stdlib.h> #include <string.h> -#include "crypto.h" +#include <openssl/md5.h> +#include <openssl/sha.h> #include "triton.h" #include "mempool.h" @@ -21,6 +22,7 @@ static int decrypt_chap_mppe_keys(struct rad_req_t *req, struct rad_attr_t *attr uint8_t md5[MD5_DIGEST_LENGTH]; uint8_t sha1[SHA_DIGEST_LENGTH]; uint8_t plain[32]; + char *secret; int i; if (attr->len != 32) { @@ -28,10 +30,14 @@ static int decrypt_chap_mppe_keys(struct rad_req_t *req, struct rad_attr_t *attr return -1; } + secret = rad_server_secret_dup(req->serv); + if (!secret) + return -1; + memcpy(plain, attr->val.octets, 32); MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, req->serv->secret, strlen(req->serv->secret)); + MD5_Update(&md5_ctx, secret, strlen(secret)); MD5_Update(&md5_ctx, req->pack->buf + 4, 16); MD5_Final(md5, &md5_ctx); @@ -39,7 +45,7 @@ static int decrypt_chap_mppe_keys(struct rad_req_t *req, struct rad_attr_t *attr plain[i] ^= md5[i]; MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, req->serv->secret, strlen(req->serv->secret)); + MD5_Update(&md5_ctx, secret, strlen(secret)); MD5_Update(&md5_ctx, attr->val.octets, 16); MD5_Final(md5, &md5_ctx); @@ -53,6 +59,7 @@ static int decrypt_chap_mppe_keys(struct rad_req_t *req, struct rad_attr_t *attr SHA1_Final(sha1, &sha1_ctx); memcpy(key, sha1, 16); + _free(secret); return 0; } @@ -62,6 +69,7 @@ static int decrypt_mppe_key(struct rad_req_t *req, struct rad_attr_t *attr, uint MD5_CTX md5_ctx; uint8_t md5[16]; uint8_t plain[32]; + char *secret; int i; if (attr->len != 34) { @@ -74,8 +82,12 @@ static int decrypt_mppe_key(struct rad_req_t *req, struct rad_attr_t *attr, uint return -1; } + secret = rad_server_secret_dup(req->serv); + if (!secret) + return -1; + MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, req->serv->secret, strlen(req->serv->secret)); + MD5_Update(&md5_ctx, secret, strlen(secret)); MD5_Update(&md5_ctx, req->pack->buf + 4, 16); MD5_Update(&md5_ctx, attr->val.octets, 2); MD5_Final(md5, &md5_ctx); @@ -87,17 +99,19 @@ static int decrypt_mppe_key(struct rad_req_t *req, struct rad_attr_t *attr, uint if (plain[0] != 16) { log_ppp_warn("radius: %s: incorrect key length (%i)\n", attr->attr->name, plain[0]); + _free(secret); return -1; } MD5_Init(&md5_ctx); - MD5_Update(&md5_ctx, req->serv->secret, strlen(req->serv->secret)); + MD5_Update(&md5_ctx, secret, strlen(secret)); MD5_Update(&md5_ctx, attr->val.octets + 2, 16); MD5_Final(md5, &md5_ctx); plain[16] ^= md5[0]; memcpy(key, plain + 1, 16); + _free(secret); return 0; } @@ -171,8 +185,7 @@ static void rad_auth_recv(struct rad_req_t *req) triton_timer_del(&req->timeout); dt = (req->reply->tv.tv_sec - req->pack->tv.tv_sec) * 1000 + (req->reply->tv.tv_nsec - req->pack->tv.tv_nsec) / 1000000; - stat_accm_add(req->serv->stat_auth_query_1m, dt); - stat_accm_add(req->serv->stat_auth_query_5m, dt); + rad_server_stat_auth_query(req->serv, dt); if (pack->code == CODE_ACCESS_ACCEPT) { if (rad_proc_attrs(req)) { @@ -207,9 +220,7 @@ static void rad_auth_timeout(struct triton_timer_t *t) rad_server_timeout(req->serv); - __sync_add_and_fetch(&req->serv->stat_auth_lost, 1); - stat_accm_add(req->serv->stat_auth_lost_1m, 1); - stat_accm_add(req->serv->stat_auth_lost_5m, 1); + rad_server_stat_auth_lost(req->serv); if (rad_req_send(req)) rad_auth_finalize(req->rpd, PWDB_DENIED); @@ -222,7 +233,7 @@ static void rad_auth_sent(struct rad_req_t *req, int res) return; } - __sync_add_and_fetch(&req->serv->stat_auth_sent, 1); + rad_server_stat_auth_sent(req->serv); if (!req->hnd.tpd) triton_md_register_handler(req->rpd->ses->ctrl->ctx, &req->hnd); @@ -277,11 +288,17 @@ int rad_auth_pap(struct radius_pd_t *rpd, const char *username, va_list args) const char *passwd = va_arg(args, const char *); uint8_t *epasswd; int epasswd_len; + char *secret; if (!req) return PWDB_DENIED; - epasswd = encrypt_password(passwd, req->serv->secret, req->RA, &epasswd_len); + secret = rad_server_secret_dup(req->serv); + if (!secret) + return PWDB_DENIED; + + epasswd = encrypt_password(passwd, secret, req->RA, &epasswd_len); + _free(secret); if (!epasswd) return PWDB_DENIED; @@ -433,7 +450,10 @@ static int rad_auth_mschap_v2_recv(struct rad_req_t *req) if (req->reply->code == CODE_ACCESS_ACCEPT) { ra = rad_packet_find_attr(req->reply, "Microsoft", "MS-CHAP2-Success"); if (!ra) { - log_error("radius:auth:mschap-v2: 'MS-CHAP-Success' not found in radius response\n"); + log_error("radius:auth:mschap-v2: 'MS-CHAP2-Success' not found in radius response\n"); + return -1; + } else if (ra->len < 43) { + log_error("radius:auth:mschap-v2: 'MS-CHAP2-Success' too short (%i)\n", ra->len); return -1; } else memcpy(rpd->auth_ctx->authenticator, ra->val.octets + 3, 40); @@ -508,4 +528,3 @@ int rad_auth_null(struct radius_pd_t *rpd, const char *username, va_list args) return PWDB_WAIT; } - diff --git a/accel-pppd/radius/dict.c b/accel-pppd/radius/dict.c index 145c5da2..c181c7cd 100644 --- a/accel-pppd/radius/dict.c +++ b/accel-pppd/radius/dict.c @@ -92,7 +92,7 @@ static int dict_load(const char *fname) continue; r = split(buf, ptr); - if (*ptr[r - 1] == '#') + if (r > 0 && *ptr[r - 1] == '#') r--; if (!strcmp(buf, "VENDOR")) { diff --git a/accel-pppd/radius/dm_coa.c b/accel-pppd/radius/dm_coa.c index e88cc347..df8cdf3e 100644 --- a/accel-pppd/radius/dm_coa.c +++ b/accel-pppd/radius/dm_coa.c @@ -10,7 +10,7 @@ #include <netinet/in.h> #include <sys/socket.h> -#include "crypto.h" +#include <openssl/md5.h> #include "triton.h" #include "events.h" @@ -106,6 +106,7 @@ static int dm_coa_send_nak(int fd, struct rad_packet_t *req, struct sockaddr_in if (err_code) rad_packet_add_int(reply, NULL, "Error-Cause", err_code); + // TODO: We need to add Message-Authenticator attribute here if (rad_packet_build(reply, RA)) { rad_packet_free(reply); return -1; @@ -266,6 +267,15 @@ static int dm_coa_read(struct triton_md_handler_t *h) rad_packet_print(pack, NULL, log_debug); } + if (rad_dae_src_check(addr.sin_addr.s_addr)) { + char ipbuf[INET_ADDRSTRLEN]; + const char *ipstr; + + ipstr = inet_ntop(AF_INET, &addr.sin_addr, ipbuf, sizeof(ipbuf)); + log_warn("radius:dm_coa: source %s not allowed\n", ipstr ? ipstr : "unknown"); + goto out_err_no_reply; + } + if (dm_coa_check_RA(pack, conf_dm_coa_secret)) { log_warn("radius:dm_coa: RA validation failed\n"); goto out_err_no_reply; diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c index 79007036..cfc0bc29 100644 --- a/accel-pppd/radius/packet.c +++ b/accel-pppd/radius/packet.c @@ -9,13 +9,25 @@ #include <linux/mman.h> #include <arpa/inet.h> +/* + * Suppress OpenSSL 3.0 deprecation warnings for HMAC API. + * See crypto.h for detailed explanation. + */ +#define OPENSSL_API_COMPAT 0x10100000L +#include <openssl/hmac.h> +#include <openssl/evp.h> + #include "log.h" #include "mempool.h" - #include "radius_p.h" +#include "attr_defs.h" #include "memdebug.h" +#define HMAC_MD5_LEN 16 +/* Radius header + attribute: type + length */ +#define PACKET_SIGNED_OFFSET (20 + 2) + static mempool_t packet_pool; static mempool_t attr_pool; static mempool_t buf_pool; @@ -47,6 +59,34 @@ void print_buf(uint8_t *buf,int size) printf("\n"); } + +int hmac_md5(const uint8_t *key, size_t key_len, + const uint8_t *data, size_t data_len, + uint8_t out[HMAC_MD5_LEN]) +{ + unsigned int len = 0; + HMAC_CTX *ctx = HMAC_CTX_new(); + if (!ctx) + return -1; + + if (HMAC_Init_ex(ctx, key, (int)key_len, EVP_md5(), NULL) != 1) + goto err; + + if (HMAC_Update(ctx, data, data_len) != 1) + goto err; + + if (HMAC_Final(ctx, out, &len) != 1 || len != HMAC_MD5_LEN) + goto err; + + HMAC_CTX_free(ctx); + return 0; + +err: + HMAC_CTX_free(ctx); + return -1; +} + + int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA) { struct rad_attr_t *attr; @@ -127,9 +167,8 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr) if (!pack) return 0; - //ptr = mmap(NULL, REQ_LENGTH_MAX, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); ptr = mempool_alloc(buf_pool); - if (ptr == MAP_FAILED) { + if (!ptr) { log_emerg("radius:packet: out of memory\n"); goto out_err; } @@ -139,7 +178,7 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr) while (1) { if (addr) - n = recvfrom(fd, pack->buf, REQ_LENGTH_MAX, 0, addr, &addr_len); + n = recvfrom(fd, pack->buf, REQ_LENGTH_MAX, 0, (struct sockaddr *)addr, &addr_len); else n = read(fd, pack->buf, REQ_LENGTH_MAX); if (n < 0) { @@ -184,9 +223,17 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr) goto out_err; } if (id == 26) { + if (len < 4) { + log_ppp_warn("radius:packet: vendor attribute too short (%i)\n", len); + goto out_err; + } vendor_id = ntohl(*(uint32_t *)ptr); vendor = rad_dict_find_vendor_id(vendor_id); if (vendor) { + if (len < 4 + vendor->tag + vendor->len) { + log_ppp_warn("radius:packet: vendor %i attribute too short (%i)\n", vendor_id, len); + goto out_err; + } ptr += 4; if (vendor->tag == 2) @@ -245,9 +292,10 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr) attr->val.octets = ptr; break; case ATTR_TYPE_INTEGER: - if (len != da->size) + if (len != da->size) { log_ppp_warn("radius:packet: attribute %s has invalid length %i (must be %i)\n", da->name, len, da->size); - case ATTR_TYPE_DATE: + break; + } if (len == 4) attr->val.integer = ntohl(*(uint32_t*)ptr); else if (len == 2) @@ -255,6 +303,12 @@ int rad_packet_recv(int fd, struct rad_packet_t **p, struct sockaddr_in *addr) else if (len == 1) attr->val.integer = *ptr; break; + case ATTR_TYPE_DATE: + if (len == 4) + attr->val.integer = ntohl(*(uint32_t*)ptr); + else + log_ppp_warn("radius:packet: attribute %s has invalid length %i (must be 4)\n", da->name, len); + break; case ATTR_TYPE_IPADDR: case ATTR_TYPE_IFID: case ATTR_TYPE_IPV6ADDR: @@ -302,6 +356,9 @@ void rad_packet_free(struct rad_packet_t *pack) mempool_free(pack->buf); //munmap(pack->buf, REQ_LENGTH_MAX); + if (pack->secret) + _free(pack->secret); + while(!list_empty(&pack->attrs)) { attr = list_entry(pack->attrs.next, typeof(*attr), entry); list_del(&attr->entry); @@ -811,9 +868,21 @@ int rad_packet_send(struct rad_packet_t *pack, int fd, struct sockaddr_in *addr) clock_gettime(CLOCK_MONOTONIC, &pack->tv); + if (pack->secret && pack->message_authenticator) { + uint8_t hmac[HMAC_MD5_LEN]; + uint8_t *ptr = pack->buf; + uint8_t *hmac_ptr = ptr + PACKET_SIGNED_OFFSET; + if (hmac_md5((const uint8_t *)pack->secret, strlen((const char *)pack->secret), pack->buf, pack->len, hmac) < 0) { + log_emerg("radius:packet: failed to calculate HMAC\n"); + return -1; + } + memcpy(hmac_ptr, hmac, HMAC_MD5_LEN); + } + + while (1) { if (addr) - n = sendto(fd, pack->buf, pack->len, 0, addr, sizeof(*addr)); + n = sendto(fd, pack->buf, pack->len, 0, (struct sockaddr *)addr, sizeof(*addr)); else n = write(fd, pack->buf, pack->len); if (n < 0) { diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c index 2406ba04..cb53f59a 100644 --- a/accel-pppd/radius/radius.c +++ b/accel-pppd/radius/radius.c @@ -2,6 +2,7 @@ #include <stdlib.h> #include <stdarg.h> #include <stdbool.h> +#include <ctype.h> #include <stdio.h> #include <string.h> #include <unistd.h> @@ -58,102 +59,314 @@ static int conf_strip_realm; const char *conf_attr_tunnel_type; int conf_acct_delay_start; +int conf_blast_protection; +int conf_framed_route_strict; static LIST_HEAD(sessions); static pthread_rwlock_t sessions_lock = PTHREAD_RWLOCK_INITIALIZER; +struct dae_allow_range { + struct list_head entry; + uint32_t begin; + uint32_t end; +}; + +static struct list_head *dae_allow_ranges; +static pthread_rwlock_t dae_allow_lock = PTHREAD_RWLOCK_INITIALIZER; + static void *pd_key; static struct ipdb_t ipdb; static mempool_t rpd_pool; static mempool_t auth_ctx_pool; -static void parse_framed_route(struct radius_pd_t *rpd, const char *attr) +static int rad_add_framed_ipv6_route(const char *str, struct radius_pd_t *rpd); + +static int ipv4_mask_to_prefix(struct in_addr mask, int *plen) { - char str[32]; - char *ptr; - long int prio = 0; - in_addr_t dst; - in_addr_t gw; - int mask; - struct framed_route *fr; + uint32_t m = ntohl(mask.s_addr); + uint32_t inv = ~m; + int p = 0; - ptr = strchr(attr, '/'); - if (ptr && ptr - attr > 16) - goto out_err; + if (inv & (inv + 1)) + return -1; - if (ptr) { - memcpy(str, attr, ptr - attr); - str[ptr - attr] = 0; - } else { - ptr = strchr(attr, ' '); - if (ptr) { - memcpy(str, attr, ptr - attr); - str[ptr - attr] = 0; - } else - strcpy(str, attr); + while (m & 0x80000000) { + p++; + m <<= 1; } - dst = inet_addr(str); - if (dst == INADDR_NONE) - goto out_err; + *plen = p; + return 0; +} + +static int parse_framed_route_v4(const char *str, struct framed_route *fr) +{ + const char *ptr; + size_t len; + struct in_addr dst; + struct in_addr gw; + struct in_addr mask_addr; + uint8_t plen; + uint32_t prio; + uint32_t mask = 0; + uint32_t addr_hbo; + + // Take a steady breath and skip leading RFC-style spaces so everything starts clean. + ptr = str + u_parse_spaces(str); + + len = u_parse_ip4cidr(ptr, &dst, &plen); + if (len) { + // Happy path: CIDR tells us exactly what we need. + fr->dst = dst.s_addr; + fr->mask = plen; + mask = plen ? (0xffffffffu << (32 - plen)) : 0; + ptr += len; + } else { + // If CIDR didn't show up, we gently switch to plain IPv4 and optional mask. + len = u_parse_ip4addr(ptr, &dst); + if (!len) + return -1; + fr->dst = dst.s_addr; + ptr += len; - if (ptr) { if (*ptr == '/') { - char *ptr2; - for (ptr2 = ++ptr; *ptr2 && *ptr2 != '.' && *ptr2 != ' '; ptr2++); - if (*ptr2 == '.' && ptr2 - ptr <= 16) { - in_addr_t a; - memcpy(str, ptr, ptr2 - ptr); - str[ptr2 - ptr] = 0; - a = ntohl(inet_addr(str)); - if (a == INADDR_NONE) - goto out_err; - mask = 33 - htonl(inet_addr(str)); - if (~((1<<(32 - mask)) - 1) != a) - goto out_err; - } else if (*ptr2 == ' ' || *ptr2 == 0) { - char *ptr3; - mask = strtol(ptr, &ptr3, 10); - if (mask < 0 || mask > 32 || ptr3 != ptr2) - goto out_err; - } else - goto out_err; + ptr++; + len = u_parse_ip4addr(ptr, &mask_addr); + if (len) { + if (ipv4_mask_to_prefix(mask_addr, &fr->mask)) + return -1; + mask = ntohl(mask_addr.s_addr); + ptr += len; + } else { + len = u_parse_u8(ptr, &plen); + if (!len || plen > 32) + return -1; + fr->mask = plen; + mask = plen ? (0xffffffffu << (32 - plen)) : 0; + ptr += len; + } } else - mask = 32; - - for (++ptr; *ptr && *ptr != ' '; ptr++); - if (*ptr == ' ') - gw = inet_addr(ptr + 1); - else if (*ptr == 0) - gw = 0; - else - goto out_err; - - /* Parse priority, if any */ - if (*ptr) { - for (++ptr; *ptr && *ptr != ' '; ptr++); - if (*ptr == ' ') - if (u_readlong(&prio, ptr + 1, 0, UINT32_MAX) < 0) - goto out_err; - } - } else { - mask = 32; - gw = 0; + fr->mask = 32; + } + + if (!mask) + mask = fr->mask ? (0xffffffffu << (32 - fr->mask)) : 0; + + if (conf_framed_route_strict) { + addr_hbo = ntohl(fr->dst); + if (addr_hbo & ~mask) + return -1; + } + + // If the string ends here, we can relax: no gateway or metric specified. + ptr += u_parse_spaces(ptr); + if (u_parse_endstr(ptr)) { + fr->gw = 0; + fr->prio = 0; + return 0; + } + + len = u_parse_ip4addr(ptr, &gw); + if (!len) + return -1; + fr->gw = gw.s_addr; + ptr += len; + + ptr += u_parse_spaces(ptr); + if (u_parse_endstr(ptr)) { + fr->prio = 0; + return 0; } - fr = _malloc(sizeof (*fr)); - fr->dst = dst; - fr->mask = mask; - fr->gw = gw; + len = u_parse_u32(ptr, &prio); + if (!len) + return -1; + ptr += len; + + if (!u_parse_endstr(ptr)) + return -1; + fr->prio = prio; + return 0; +} + +static void parse_framed_route(struct radius_pd_t *rpd, const char *attr) +{ + struct framed_route *fr; + + /* RFC 2865: Framed-Route is IPv4-only and uses spaces; IPv6 lives in Framed-IPv6-Route. */ + if (strchr(attr, ':')) { + log_ppp_warn("radius: Framed-Route is IPv4-only per RFC 2865, use Framed-IPv6-Route for %s\n", attr); + return; + } + + fr = _malloc(sizeof(*fr)); + if (!fr) + goto out_err; + memset(fr, 0, sizeof(*fr)); + + if (parse_framed_route_v4(attr, fr) < 0) + goto out_err_free; + fr->next = rpd->fr; rpd->fr = fr; return; +out_err_free: + _free(fr); out_err: - log_ppp_warn("radius: failed to parse Framed-Route=%s\n", attr); + log_ppp_warn("radius: failed to parse Framed-Route=\"%s\" (expected \"dst[/mask] gw [metric]\"; check destination, mask, gateway, and metric fields)\n", attr); +} + +static char *trim_spaces(char *str) +{ + char *end; + + while (isspace((unsigned char)*str)) + ++str; + + if (*str == '\0') + return str; + + end = str + strlen(str) - 1; + while (end > str && isspace((unsigned char)*end)) { + *end = '\0'; + --end; + } + + return str; +} + +static void dae_allow_clear(void) +{ + struct dae_allow_range *range; + + if (!dae_allow_ranges) + return; + + while (!list_empty(dae_allow_ranges)) { + range = list_first_entry(dae_allow_ranges, typeof(*range), entry); + list_del(&range->entry); + _free(range); + } + + _free(dae_allow_ranges); + dae_allow_ranges = NULL; +} + +static int dae_allow_add(uint32_t begin, uint32_t end) +{ + struct dae_allow_range *range; + + if (!dae_allow_ranges) + return -1; + + range = _malloc(sizeof(*range)); + if (!range) + return -1; + + range->begin = begin; + range->end = end; + list_add_tail(&range->entry, dae_allow_ranges); + + return 0; +} + +static int dae_allow_parse_token(const char *token, uint32_t *begin, uint32_t *end) +{ + struct in_addr base_addr; + uint8_t suffix; + size_t len; + + len = u_parse_ip4cidr(token, &base_addr, &suffix); + if (len && token[len] == '\0') { + uint32_t addr_hbo = ntohl(base_addr.s_addr); + uint32_t mask = (uint64_t)0xffffffff << (32 - suffix); + uint32_t ip_min = addr_hbo & mask; + + *begin = ip_min; + *end = addr_hbo | ~mask; + if (ip_min != addr_hbo) { + struct in_addr min_addr = { .s_addr = htonl(ip_min) }; + char ipbuf[INET_ADDRSTRLEN]; + + log_warn("radius: dae-allowed network %s is equivalent to %s/%hhu\n", + token, u_ip4str(&min_addr, ipbuf), suffix); + } + return 0; + } + + if (!inet_aton(token, &base_addr)) + return -1; + + *begin = ntohl(base_addr.s_addr); + *end = *begin; + return 0; +} + +static int dae_allow_parse(const char *opt, int *entries) +{ + char *dup; + char *token; + char *saveptr; + int count = 0; + + dup = _strdup(opt); + if (!dup) + return -1; + + for (token = strtok_r(dup, ",", &saveptr); token; + token = strtok_r(NULL, ",", &saveptr)) { + char *trimmed = trim_spaces(token); + uint32_t begin; + uint32_t end; + + if (*trimmed == '\0') + continue; + + if (dae_allow_parse_token(trimmed, &begin, &end)) { + log_warn("radius: dae-allowed invalid entry \"%s\"\n", trimmed); + continue; + } + + if (dae_allow_add(begin, end)) { + _free(dup); + return -1; + } + + ++count; + } + + _free(dup); + *entries = count; + return 0; +} + +static int dae_allow_check(in_addr_t ipaddr) +{ + struct dae_allow_range *range; + uint32_t addr = ntohl(ipaddr); + + list_for_each_entry(range, dae_allow_ranges, entry) { + if (addr >= range->begin && addr <= range->end) + return 0; + } + + return -1; +} + +int rad_dae_src_check(in_addr_t ipaddr) +{ + int res = 0; + + pthread_rwlock_rdlock(&dae_allow_lock); + if (dae_allow_ranges) + res = dae_allow_check(ipaddr); + pthread_rwlock_unlock(&dae_allow_lock); + + return res; } /* Parse a RADIUS Framed-IPv6-Route string. @@ -641,8 +854,7 @@ static void ses_started(struct ap_session *ses) bool gw_spec = !IN6_IS_ADDR_UNSPECIFIED(&fr6->gw); char nbuf[INET6_ADDRSTRLEN]; char gwbuf[INET6_ADDRSTRLEN]; - - if (ip6route_add(gw_spec ? 0 : rpd->ses->ifindex, &fr6->prefix, fr6->plen, gw_spec ? &fr6->gw : NULL, 3, fr6->prio)) { + if (ip6route_add(gw_spec ? 0 : rpd->ses->ifindex, &fr6->prefix, fr6->plen, gw_spec ? &fr6->gw : NULL, 3, fr6->prio, rpd->ses->vrf_name)) { log_ppp_warn("radius: failed to add route %s/%hhu %s %u\n", u_ip6str(&fr6->prefix, nbuf), fr6->plen, u_ip6str(&fr6->gw, gwbuf), fr6->prio); @@ -650,7 +862,7 @@ static void ses_started(struct ap_session *ses) } for (fr = rpd->fr; fr; fr = fr->next) { - if (iproute_add(fr->gw ? 0 : rpd->ses->ifindex, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio)) { + if (iproute_add(fr->gw ? 0 : rpd->ses->ifindex, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio, rpd->ses->vrf_name)) { char dst[17], gw[17]; u_inet_ntoa(fr->dst, dst); u_inet_ntoa(fr->gw, gw); @@ -689,12 +901,12 @@ static void ses_finishing(struct ap_session *ses) * when the interface is removed. */ if (!IN6_IS_ADDR_UNSPECIFIED(&fr6->gw)) - ip6route_del(0, &fr6->prefix, fr6->plen, &fr6->gw, 3, fr6->prio); + ip6route_del(0, &fr6->prefix, fr6->plen, &fr6->gw, 3, fr6->prio, rpd->ses->vrf_name); } for (fr = rpd->fr; fr; fr = fr->next) { if (fr->gw) - iproute_del(0, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio); + iproute_del(0, 0, fr->dst, fr->gw, 3, fr->mask, fr->prio, rpd->ses->vrf_name); } if (rpd->acct_started || rpd->acct_req) @@ -1046,6 +1258,42 @@ static int load_config(void) return -1; } + { + int entries = 0; + int dae_allowed_present = 0; + int parse_rc = 0; + + pthread_rwlock_wrlock(&dae_allow_lock); + dae_allow_clear(); + opt = conf_get_opt("radius", "dae-allowed"); + if (opt) { + dae_allowed_present = 1; + dae_allow_ranges = _malloc(sizeof(*dae_allow_ranges)); + if (!dae_allow_ranges) { + log_emerg("radius: failed to allocate dae-allowed list\n"); + parse_rc = -1; + goto dae_allow_unlock; + } + INIT_LIST_HEAD(dae_allow_ranges); + if (dae_allow_parse(opt, &entries)) { + log_emerg("radius: failed to parse dae-allowed\n"); + dae_allow_clear(); + parse_rc = -1; + goto dae_allow_unlock; + } + } + + if (dae_allowed_present && entries == 0) { + log_warn("radius: dae-allowed has no valid entries, DAE source restrictions are disabled\n"); + dae_allow_clear(); + } + +dae_allow_unlock: + pthread_rwlock_unlock(&dae_allow_lock); + if (parse_rc) + return -1; + } + opt = conf_get_opt("radius", "sid-in-auth"); if (opt) conf_sid_in_auth = atoi(opt); @@ -1086,6 +1334,18 @@ static int load_config(void) else conf_acct_delay_start = 0; + opt = conf_get_opt("radius", "blast-protection"); + if (opt && atoi(opt) > 0) { + conf_blast_protection = 1; + } else { + conf_blast_protection = 0; + } + opt = conf_get_opt("radius", "framed-route-strict"); + if (opt && atoi(opt) > 0) + conf_framed_route_strict = 1; + else + conf_framed_route_strict = 0; + return 0; } diff --git a/accel-pppd/radius/radius.h b/accel-pppd/radius/radius.h index 1925c973..c19b25c2 100644 --- a/accel-pppd/radius/radius.h +++ b/accel-pppd/radius/radius.h @@ -103,6 +103,8 @@ struct rad_attr_t struct rad_packet_t { + int message_authenticator; // 1 if message authenticator is required + uint8_t *secret; // shared secret for this packet for Message-Authenticator signature int code; uint8_t id; int len; diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h index 87613624..d3a72204 100644 --- a/accel-pppd/radius/radius_p.h +++ b/accel-pppd/radius/radius_p.h @@ -115,6 +115,31 @@ struct rad_req_t { void (*log)(const char *fmt, ...); }; +struct rad_server_stat_t { + unsigned long auth_sent; + unsigned long auth_lost; + unsigned long acct_sent; + unsigned long acct_lost; + unsigned long interim_sent; + unsigned long interim_lost; + unsigned long fail_cnt; + + struct stat_accm_t *auth_lost_1m; + struct stat_accm_t *auth_lost_5m; + struct stat_accm_t *auth_query_1m; + struct stat_accm_t *auth_query_5m; + + struct stat_accm_t *acct_lost_1m; + struct stat_accm_t *acct_lost_5m; + struct stat_accm_t *acct_query_1m; + struct stat_accm_t *acct_query_5m; + + struct stat_accm_t *interim_lost_1m; + struct stat_accm_t *interim_lost_5m; + struct stat_accm_t *interim_query_1m; + struct stat_accm_t *interim_query_5m; +}; + struct rad_server_t { struct list_head entry; struct triton_context_t ctx; @@ -139,28 +164,7 @@ struct rad_server_t { int weight; pthread_mutex_t lock; - unsigned long stat_auth_sent; - unsigned long stat_auth_lost; - unsigned long stat_acct_sent; - unsigned long stat_acct_lost; - unsigned long stat_interim_sent; - unsigned long stat_interim_lost; - unsigned long stat_fail_cnt; - - struct stat_accm_t *stat_auth_lost_1m; - struct stat_accm_t *stat_auth_lost_5m; - struct stat_accm_t *stat_auth_query_1m; - struct stat_accm_t *stat_auth_query_5m; - - struct stat_accm_t *stat_acct_lost_1m; - struct stat_accm_t *stat_acct_lost_5m; - struct stat_accm_t *stat_acct_query_1m; - struct stat_accm_t *stat_acct_query_5m; - - struct stat_accm_t *stat_interim_lost_1m; - struct stat_accm_t *stat_interim_lost_5m; - struct stat_accm_t *stat_interim_query_1m; - struct stat_accm_t *stat_interim_query_5m; + struct rad_server_stat_t stat; unsigned int backup:1; unsigned int starting:1; @@ -198,6 +202,7 @@ extern int conf_acct_interim_jitter; extern int conf_accounting; extern const char *conf_attr_tunnel_type; extern int conf_acct_delay_start; +extern int conf_blast_protection; int rad_check_nas_pack(struct rad_packet_t *pack); struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, const char *port_id, int port, in_addr_t ipaddr, const char *csid); @@ -210,7 +215,7 @@ struct rad_req_t *rad_req_alloc(struct radius_pd_t *rpd, int code, const char *u struct rad_req_t *rad_req_alloc2(struct radius_pd_t *rpd, int code, const char *username, in_addr_t addr, int port); struct rad_req_t *rad_req_alloc_empty(); int rad_req_acct_fill(struct rad_req_t *); -void rad_req_free(struct rad_req_t *); +struct rad_server_t *rad_req_free(struct rad_req_t *); int rad_req_send(struct rad_req_t *req); int __rad_req_send(struct rad_req_t *req, int async); int rad_req_read(struct triton_md_handler_t *h); @@ -239,10 +244,12 @@ void rad_packet_print(struct rad_packet_t *pack, struct rad_server_t *s, void (* int rad_packet_send(struct rad_packet_t *pck, int fd, struct sockaddr_in *addr); void dm_coa_cancel(struct radius_pd_t *pd); +int rad_dae_src_check(in_addr_t ipaddr); struct rad_server_t *rad_server_get(int); struct rad_server_t *rad_server_get2(int, in_addr_t, int); -void rad_server_put(struct rad_server_t *, int); +struct rad_server_t *rad_server_put(struct rad_server_t *, int); +char *rad_server_secret_dup(struct rad_server_t *); int rad_server_req_enter(struct rad_req_t *); void rad_server_req_exit(struct rad_req_t *); int rad_server_req_cancel(struct rad_req_t *, int full); @@ -250,6 +257,16 @@ int rad_server_realloc(struct rad_req_t *); void rad_server_fail(struct rad_server_t *); void rad_server_timeout(struct rad_server_t *); void rad_server_reply(struct rad_server_t *); +void rad_server_stat_fail(struct rad_server_t *); +void rad_server_stat_auth_sent(struct rad_server_t *); +void rad_server_stat_auth_lost(struct rad_server_t *); +void rad_server_stat_auth_query(struct rad_server_t *, unsigned int dt); +void rad_server_stat_acct_sent(struct rad_server_t *); +void rad_server_stat_acct_lost(struct rad_server_t *); +void rad_server_stat_acct_query(struct rad_server_t *, unsigned int dt); +void rad_server_stat_interim_sent(struct rad_server_t *); +void rad_server_stat_interim_lost(struct rad_server_t *); +void rad_server_stat_interim_query(struct rad_server_t *, unsigned int dt); void rad_update_session_timeout(struct radius_pd_t *rpd, int timeout); @@ -266,4 +283,3 @@ unsigned long stat_accm_get_cnt(struct stat_accm_t *); unsigned long stat_accm_get_avg(struct stat_accm_t *); #endif - diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c index be74f047..72c46b16 100644 --- a/accel-pppd/radius/req.c +++ b/accel-pppd/radius/req.c @@ -15,6 +15,8 @@ #include "memdebug.h" +#define HMAC_MD5_LEN 16 + static int make_socket(struct rad_req_t *req); static mempool_t req_pool; @@ -73,6 +75,19 @@ static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, cons if (!req->pack) goto out_err; + if (code == CODE_ACCESS_REQUEST && conf_blast_protection) { + uint8_t buf[HMAC_MD5_LEN] = {0}; + req->pack->message_authenticator = 1; + req->pack->secret = (uint8_t *)rad_server_secret_dup(req->serv); + if (!req->pack->secret) + goto out_err; + if (rad_packet_add_octets(req->pack, NULL, "Message-Authenticator", buf, HMAC_MD5_LEN)) { + _free(req->pack->secret); + req->pack->secret = NULL; + goto out_err; + } + } + if (code == CODE_ACCOUNTING_REQUEST && rpd->acct_username) username = rpd->acct_username; @@ -242,13 +257,15 @@ int rad_req_acct_fill(struct rad_req_t *req) return 0; } -void rad_req_free(struct rad_req_t *req) +struct rad_server_t *rad_req_free(struct rad_req_t *req) { + struct rad_server_t *s = NULL; + assert(!req->active); assert(!req->entry.next); if (req->serv) - rad_server_put(req->serv, req->type); + s = rad_server_put(req->serv, req->type); if (req->hnd.tpd) triton_md_unregister_handler(&req->hnd, 1); @@ -265,6 +282,8 @@ void rad_req_free(struct rad_req_t *req) rad_packet_free(req->reply); mempool_free(req); + + return s; } static int make_socket(struct rad_req_t *req) diff --git a/accel-pppd/radius/serv.c b/accel-pppd/radius/serv.c index 4af6a67a..71398c82 100644 --- a/accel-pppd/radius/serv.c +++ b/accel-pppd/radius/serv.c @@ -11,14 +11,14 @@ #include <netinet/in.h> #include <arpa/inet.h> +#include <openssl/md5.h> + #include "log.h" #include "triton.h" #include "events.h" #include "cli.h" #include "utils.h" -#include "crypto.h" - #include "radius_p.h" #include "memdebug.h" @@ -93,16 +93,35 @@ struct rad_server_t *rad_server_get2(int type, in_addr_t addr, int port) return __rad_server_get(type, NULL, addr, port); } -void rad_server_put(struct rad_server_t *s, int type) +struct rad_server_t *rad_server_put(struct rad_server_t *s, int type) { + int do_close = 0; + int do_free = 0; + __sync_sub_and_fetch(&s->client_cnt[type], 1); if ((s->need_free || s->need_close) && !s->client_cnt[0] && !s->client_cnt[1]) { - if (s->need_close) + if (s->need_close) { + do_close = 1; triton_context_call(&s->ctx, (triton_event_func)serv_ctx_close, &s->ctx); - else + } else { + do_free = 1; __free_server(s); - } + } + } + + return (do_free || do_close) ? NULL : s; +} + +char *rad_server_secret_dup(struct rad_server_t *s) +{ + char *secret; + + pthread_mutex_lock(&s->lock); + secret = _strdup(s->secret); + pthread_mutex_unlock(&s->lock); + + return secret; } static void req_wakeup(struct rad_req_t *req) @@ -133,7 +152,20 @@ static void req_wakeup(struct rad_req_t *req) } pthread_mutex_unlock(&req->serv->lock); - req->send(req, 1); + if (req->send(req, 1) == -2) { + /* socket setup failed: release the slot taken in + * rad_server_req_exit() and drive the failover path, + * otherwise the server's req_cnt leaks and the request + * is orphaned */ + req->active = 0; + pthread_mutex_lock(&req->serv->lock); + req->serv->req_cnt--; + pthread_mutex_unlock(&req->serv->lock); + + rad_server_fail(req->serv); + + req->send(req, -1); + } } static void req_wakeup_failed(struct rad_req_t *req) @@ -338,7 +370,7 @@ void rad_server_fail(struct rad_server_t *s) } s->queue_cnt = 0; - s->stat_fail_cnt++; + rad_server_stat_fail(s); pthread_mutex_unlock(&s->lock); } @@ -358,18 +390,86 @@ void rad_server_reply(struct rad_server_t *s) s->timeout_cnt = 0; } -static int req_set_RA(struct rad_req_t *req, const char *secret) +void rad_server_stat_fail(struct rad_server_t *s) +{ + __atomic_add_fetch(&s->stat.fail_cnt, 1, __ATOMIC_RELAXED); +} + +void rad_server_stat_auth_sent(struct rad_server_t *s) +{ + __atomic_add_fetch(&s->stat.auth_sent, 1, __ATOMIC_RELAXED); +} + +void rad_server_stat_auth_lost(struct rad_server_t *s) +{ + __atomic_add_fetch(&s->stat.auth_lost, 1, __ATOMIC_RELAXED); + stat_accm_add(s->stat.auth_lost_1m, 1); + stat_accm_add(s->stat.auth_lost_5m, 1); +} + +void rad_server_stat_auth_query(struct rad_server_t *s, unsigned int dt) +{ + stat_accm_add(s->stat.auth_query_1m, dt); + stat_accm_add(s->stat.auth_query_5m, dt); +} + +void rad_server_stat_acct_sent(struct rad_server_t *s) +{ + __atomic_add_fetch(&s->stat.acct_sent, 1, __ATOMIC_RELAXED); +} + +void rad_server_stat_acct_lost(struct rad_server_t *s) +{ + __atomic_add_fetch(&s->stat.acct_lost, 1, __ATOMIC_RELAXED); + stat_accm_add(s->stat.acct_lost_1m, 1); + stat_accm_add(s->stat.acct_lost_5m, 1); +} + +void rad_server_stat_acct_query(struct rad_server_t *s, unsigned int dt) +{ + stat_accm_add(s->stat.acct_query_1m, dt); + stat_accm_add(s->stat.acct_query_5m, dt); +} + +void rad_server_stat_interim_sent(struct rad_server_t *s) +{ + __atomic_add_fetch(&s->stat.interim_sent, 1, __ATOMIC_RELAXED); +} + +void rad_server_stat_interim_lost(struct rad_server_t *s) +{ + __atomic_add_fetch(&s->stat.interim_lost, 1, __ATOMIC_RELAXED); + stat_accm_add(s->stat.interim_lost_1m, 1); + stat_accm_add(s->stat.interim_lost_5m, 1); +} + +void rad_server_stat_interim_query(struct rad_server_t *s, unsigned int dt) +{ + stat_accm_add(s->stat.interim_query_1m, dt); + stat_accm_add(s->stat.interim_query_5m, dt); +} + +static int req_set_RA(struct rad_req_t *req) { + char *secret; MD5_CTX ctx; - if (rad_packet_build(req->pack, req->RA)) + secret = rad_server_secret_dup(req->serv); + if (!secret) return -1; + if (rad_packet_build(req->pack, req->RA)) { + _free(secret); + return -1; + } + MD5_Init(&ctx); MD5_Update(&ctx, req->pack->buf, req->pack->len); MD5_Update(&ctx, secret, strlen(secret)); MD5_Final(req->pack->buf + 4, &ctx); + _free(secret); + return 0; } @@ -383,13 +483,14 @@ static void acct_on_sent(struct rad_req_t *req, int res) static void acct_on_recv(struct rad_req_t *req) { - struct rad_server_t *s = req->serv; + struct rad_server_t *s = rad_req_free(req); - rad_req_free(req); + if (!s) + return; - if (req->serv->starting) { - req->serv->starting = 0; - req->serv->acct_on = 1; + if (s->starting) { + s->starting = 0; + s->acct_on = 1; } else __free_server(s); } @@ -397,12 +498,15 @@ static void acct_on_recv(struct rad_req_t *req) static void acct_on_timeout(struct triton_timer_t *t) { struct rad_req_t *req = container_of(t, typeof(*req), timeout); - struct rad_server_t *s = req->serv; log_switch(triton_context_self(), NULL); if (req->try++ == conf_max_try) { - rad_req_free(req); + struct rad_server_t *s = rad_req_free(req); + + if (!s) + return; + if (s->starting) s->starting = 0; else @@ -416,6 +520,8 @@ static void acct_on_timeout(struct triton_timer_t *t) static void send_acct_on(struct rad_server_t *s) { struct rad_req_t *req = rad_req_alloc_empty(); + if (!req) + return; log_switch(triton_context_self(), NULL); @@ -450,7 +556,7 @@ static void send_acct_on(struct rad_server_t *s) if (rad_packet_add_ipaddr(req->pack, NULL, "NAS-IP-Address", conf_nas_ip_address)) goto out_err; - if (req_set_RA(req, s->secret)) + if (req_set_RA(req)) goto out_err; __rad_req_send(req, 0); @@ -483,10 +589,66 @@ static void serv_ctx_close(struct triton_context_t *ctx) } } +struct rad_server_stat_snapshot_t { + int req_cnt; + int queue_cnt; + unsigned long auth_sent; + unsigned long auth_lost; + unsigned long auth_lost_1m; + unsigned long auth_lost_5m; + unsigned long auth_query_1m; + unsigned long auth_query_5m; + unsigned long acct_sent; + unsigned long acct_lost; + unsigned long acct_lost_1m; + unsigned long acct_lost_5m; + unsigned long acct_query_1m; + unsigned long acct_query_5m; + unsigned long interim_sent; + unsigned long interim_lost; + unsigned long interim_lost_1m; + unsigned long interim_lost_5m; + unsigned long interim_query_1m; + unsigned long interim_query_5m; + unsigned long fail_cnt; +}; + +static void rad_server_stat_get(struct rad_server_t *s, struct rad_server_stat_snapshot_t *stat) +{ + pthread_mutex_lock(&s->lock); + stat->req_cnt = s->req_cnt; + stat->queue_cnt = s->queue_cnt; + pthread_mutex_unlock(&s->lock); + + stat->auth_sent = __atomic_load_n(&s->stat.auth_sent, __ATOMIC_RELAXED); + stat->auth_lost = __atomic_load_n(&s->stat.auth_lost, __ATOMIC_RELAXED); + stat->auth_lost_1m = stat_accm_get_cnt(s->stat.auth_lost_1m); + stat->auth_lost_5m = stat_accm_get_cnt(s->stat.auth_lost_5m); + stat->auth_query_1m = stat_accm_get_avg(s->stat.auth_query_1m); + stat->auth_query_5m = stat_accm_get_avg(s->stat.auth_query_5m); + + stat->acct_sent = __atomic_load_n(&s->stat.acct_sent, __ATOMIC_RELAXED); + stat->acct_lost = __atomic_load_n(&s->stat.acct_lost, __ATOMIC_RELAXED); + stat->acct_lost_1m = stat_accm_get_cnt(s->stat.acct_lost_1m); + stat->acct_lost_5m = stat_accm_get_cnt(s->stat.acct_lost_5m); + stat->acct_query_1m = stat_accm_get_avg(s->stat.acct_query_1m); + stat->acct_query_5m = stat_accm_get_avg(s->stat.acct_query_5m); + + stat->interim_sent = __atomic_load_n(&s->stat.interim_sent, __ATOMIC_RELAXED); + stat->interim_lost = __atomic_load_n(&s->stat.interim_lost, __ATOMIC_RELAXED); + stat->interim_lost_1m = stat_accm_get_cnt(s->stat.interim_lost_1m); + stat->interim_lost_5m = stat_accm_get_cnt(s->stat.interim_lost_5m); + stat->interim_query_1m = stat_accm_get_avg(s->stat.interim_query_1m); + stat->interim_query_5m = stat_accm_get_avg(s->stat.interim_query_5m); + + stat->fail_cnt = __atomic_load_n(&s->stat.fail_cnt, __ATOMIC_RELAXED); +} + static void show_stat(struct rad_server_t *s, void *client) { char addr[INET6_ADDRSTRLEN]; // Sufficient size for both IPv4 and IPv6 addresses struct timespec ts; + struct rad_server_stat_snapshot_t stat; if (s->ipv4) { u_inet_ntoa(s->addr, addr); @@ -495,6 +657,7 @@ static void show_stat(struct rad_server_t *s, void *client) } clock_gettime(CLOCK_MONOTONIC, &ts); + rad_server_stat_get(s, &stat); cli_sendv(client, "radius(%i, %s):\r\n", s->id, addr); @@ -503,31 +666,31 @@ static void show_stat(struct rad_server_t *s, void *client) else cli_send(client, " state: active\r\n"); - cli_sendv(client, " fail count: %lu\r\n", s->stat_fail_cnt); + cli_sendv(client, " fail count: %lu\r\n", stat.fail_cnt); - cli_sendv(client, " request count: %i\r\n", s->req_cnt); - cli_sendv(client, " queue length: %i\r\n", s->queue_cnt); + cli_sendv(client, " request count: %i\r\n", stat.req_cnt); + cli_sendv(client, " queue length: %i\r\n", stat.queue_cnt); if (s->auth_port) { - cli_sendv(client, " auth sent: %lu\r\n", s->stat_auth_sent); + cli_sendv(client, " auth sent: %lu\r\n", stat.auth_sent); cli_sendv(client, " auth lost(total/5m/1m): %lu/%lu/%lu\r\n", - s->stat_auth_lost, stat_accm_get_cnt(s->stat_auth_lost_5m), stat_accm_get_cnt(s->stat_auth_lost_1m)); + stat.auth_lost, stat.auth_lost_5m, stat.auth_lost_1m); cli_sendv(client, " auth avg query time(5m/1m): %lu/%lu ms\r\n", - stat_accm_get_avg(s->stat_auth_query_5m), stat_accm_get_avg(s->stat_auth_query_1m)); + stat.auth_query_5m, stat.auth_query_1m); } if (s->acct_port) { - cli_sendv(client, " acct sent: %lu\r\n", s->stat_acct_sent); + cli_sendv(client, " acct sent: %lu\r\n", stat.acct_sent); cli_sendv(client, " acct lost(total/5m/1m): %lu/%lu/%lu\r\n", - s->stat_acct_lost, stat_accm_get_cnt(s->stat_acct_lost_5m), stat_accm_get_cnt(s->stat_acct_lost_1m)); + stat.acct_lost, stat.acct_lost_5m, stat.acct_lost_1m); cli_sendv(client, " acct avg query time(5m/1m): %lu/%lu ms\r\n", - stat_accm_get_avg(s->stat_acct_query_5m), stat_accm_get_avg(s->stat_acct_query_1m)); + stat.acct_query_5m, stat.acct_query_1m); - cli_sendv(client, " interim sent: %lu\r\n", s->stat_interim_sent); + cli_sendv(client, " interim sent: %lu\r\n", stat.interim_sent); cli_sendv(client, " interim lost(total/5m/1m): %lu/%lu/%lu\r\n", - s->stat_interim_lost, stat_accm_get_cnt(s->stat_interim_lost_5m), stat_accm_get_cnt(s->stat_interim_lost_1m)); + stat.interim_lost, stat.interim_lost_5m, stat.interim_lost_1m); cli_sendv(client, " interim avg query time(5m/1m): %lu/%lu ms\r\n", - stat_accm_get_avg(s->stat_interim_query_5m), stat_accm_get_avg(s->stat_interim_query_1m)); + stat.interim_query_5m, stat.interim_query_1m); } } @@ -544,6 +707,7 @@ static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, static void __add_server(struct rad_server_t *s) { struct rad_server_t *s1; + char *old_secret; list_for_each_entry(s1, &serv_list, entry) { if (s1->addr == s->addr && s1->auth_port == s->auth_port && s1->acct_port == s->acct_port) { @@ -553,6 +717,13 @@ static void __add_server(struct rad_server_t *s) s1->need_free = 0; s1->bind_default = s->bind_default; strcpy(s1->bind_device, s->bind_device); + /* adopt the freshly parsed secret so changes take effect on reload */ + pthread_mutex_lock(&s1->lock); + old_secret = s1->secret; + s1->secret = s->secret; + s->secret = NULL; + pthread_mutex_unlock(&s1->lock); + _free(old_secret); _free(s); return; } @@ -565,20 +736,20 @@ static void __add_server(struct rad_server_t *s) list_add_tail(&s->entry, &serv_list); s->starting = conf_acct_on; - s->stat_auth_lost_1m = stat_accm_create(60); - s->stat_auth_lost_5m = stat_accm_create(5 * 60); - s->stat_auth_query_1m = stat_accm_create(60); - s->stat_auth_query_5m = stat_accm_create(5 * 60); + s->stat.auth_lost_1m = stat_accm_create(60); + s->stat.auth_lost_5m = stat_accm_create(5 * 60); + s->stat.auth_query_1m = stat_accm_create(60); + s->stat.auth_query_5m = stat_accm_create(5 * 60); - s->stat_acct_lost_1m = stat_accm_create(60); - s->stat_acct_lost_5m = stat_accm_create(5 * 60); - s->stat_acct_query_1m = stat_accm_create(60); - s->stat_acct_query_5m = stat_accm_create(5 * 60); + s->stat.acct_lost_1m = stat_accm_create(60); + s->stat.acct_lost_5m = stat_accm_create(5 * 60); + s->stat.acct_query_1m = stat_accm_create(60); + s->stat.acct_query_5m = stat_accm_create(5 * 60); - s->stat_interim_lost_1m = stat_accm_create(60); - s->stat_interim_lost_5m = stat_accm_create(5 * 60); - s->stat_interim_query_1m = stat_accm_create(60); - s->stat_interim_query_5m = stat_accm_create(5 * 60); + s->stat.interim_lost_1m = stat_accm_create(60); + s->stat.interim_lost_5m = stat_accm_create(5 * 60); + s->stat.interim_query_1m = stat_accm_create(60); + s->stat.interim_query_5m = stat_accm_create(5 * 60); s->ctx.close = serv_ctx_close; @@ -593,23 +764,24 @@ static void __free_server(struct rad_server_t *s) { log_debug("radius: free(%i)\n", s->id); - stat_accm_free(s->stat_auth_lost_1m); - stat_accm_free(s->stat_auth_lost_5m); - stat_accm_free(s->stat_auth_query_1m); - stat_accm_free(s->stat_auth_query_5m); + stat_accm_free(s->stat.auth_lost_1m); + stat_accm_free(s->stat.auth_lost_5m); + stat_accm_free(s->stat.auth_query_1m); + stat_accm_free(s->stat.auth_query_5m); - stat_accm_free(s->stat_acct_lost_1m); - stat_accm_free(s->stat_acct_lost_5m); - stat_accm_free(s->stat_acct_query_1m); - stat_accm_free(s->stat_acct_query_5m); + stat_accm_free(s->stat.acct_lost_1m); + stat_accm_free(s->stat.acct_lost_5m); + stat_accm_free(s->stat.acct_query_1m); + stat_accm_free(s->stat.acct_query_5m); - stat_accm_free(s->stat_interim_lost_1m); - stat_accm_free(s->stat_interim_lost_5m); - stat_accm_free(s->stat_interim_query_1m); - stat_accm_free(s->stat_interim_query_5m); + stat_accm_free(s->stat.interim_lost_1m); + stat_accm_free(s->stat.interim_lost_5m); + stat_accm_free(s->stat.interim_query_1m); + stat_accm_free(s->stat.interim_query_5m); triton_context_unregister(&s->ctx); + _free(s->secret); _free(s); } diff --git a/accel-pppd/session.c b/accel-pppd/session.c index c01417f3..c16f68ae 100644 --- a/accel-pppd/session.c +++ b/accel-pppd/session.c @@ -30,6 +30,14 @@ #define SID_SOURCE_SEQ 0 #define SID_SOURCE_URANDOM 1 +#ifndef __WORDSIZE +#if defined(__GLIBC__) || defined(__UCLIBC__) +#include <bits/wordsize.h> +#else +#include <bits/reg.h> +#endif +#endif + static int conf_sid_ucase; static int conf_single_session = -1; static int conf_single_session_ignore_case; @@ -54,13 +62,58 @@ static spinlock_t seq_lock; static long long unsigned seq; static struct timespec seq_ts; -struct ap_session_stat __export ap_session_stat; +static struct ap_session_stat ap_session_stat; static void (*shutdown_cb)(void); static void generate_sessionid(struct ap_session *ses); static void save_seq(void); +void __export ap_session_stat_get(struct ap_session_stat *stat) +{ + stat->starting = __atomic_load_n(&ap_session_stat.starting, __ATOMIC_RELAXED); + stat->active = __atomic_load_n(&ap_session_stat.active, __ATOMIC_RELAXED); + stat->finishing = __atomic_load_n(&ap_session_stat.finishing, __ATOMIC_RELAXED); +} + +unsigned int __export ap_session_stat_starting(void) +{ + return __atomic_load_n(&ap_session_stat.starting, __ATOMIC_RELAXED); +} + +unsigned int __export ap_session_stat_active(void) +{ + return __atomic_load_n(&ap_session_stat.active, __ATOMIC_RELAXED); +} + +unsigned int __export ap_session_stat_finishing(void) +{ + return __atomic_load_n(&ap_session_stat.finishing, __ATOMIC_RELAXED); +} + +static void ap_session_stat_inc(unsigned int *stat) +{ + __atomic_add_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void ap_session_stat_dec(unsigned int *stat) +{ + __atomic_sub_fetch(stat, 1, __ATOMIC_RELAXED); +} + +static void ap_session_stat_move(unsigned int *from, unsigned int *to) +{ + ap_session_stat_dec(from); + ap_session_stat_inc(to); +} + +static int ap_session_stat_idle(void) +{ + return !ap_session_stat_starting() + && !ap_session_stat_active() + && !ap_session_stat_finishing(); +} + void __export ap_session_init(struct ap_session *ses) { memset(ses, 0, sizeof(*ses)); @@ -105,7 +158,7 @@ int __export ap_session_starting(struct ap_session *ses) ses->state = AP_STATE_STARTING; } - __sync_add_and_fetch(&ap_session_stat.starting, 1); + ap_session_stat_inc(&ap_session_stat.starting); pthread_rwlock_wrlock(&ses_lock); list_add_tail(&ses->entry, &ses_list); @@ -148,8 +201,7 @@ void __export ap_session_activate(struct ap_session *ses) return; ses->state = AP_STATE_ACTIVE; - __sync_sub_and_fetch(&ap_session_stat.starting, 1); - __sync_add_and_fetch(&ap_session_stat.active, 1); + ap_session_stat_move(&ap_session_stat.starting, &ap_session_stat.active); if (!ses->session_timeout && conf_session_timeout) ses->session_timeout = conf_session_timeout; @@ -178,7 +230,6 @@ void __export ap_session_finished(struct ap_session *ses) if (!ses->down) { ap_session_ifdown(ses); - ap_session_read_stats(ses, NULL); triton_event_fire(EV_SES_FINISHING, ses); } @@ -191,14 +242,14 @@ void __export ap_session_finished(struct ap_session *ses) switch (ses->state) { case AP_STATE_ACTIVE: - __sync_sub_and_fetch(&ap_session_stat.active, 1); + ap_session_stat_dec(&ap_session_stat.active); break; case AP_STATE_RESTORE: case AP_STATE_STARTING: - __sync_sub_and_fetch(&ap_session_stat.starting, 1); + ap_session_stat_dec(&ap_session_stat.starting); break; case AP_STATE_FINISHING: - __sync_sub_and_fetch(&ap_session_stat.finishing, 1); + ap_session_stat_dec(&ap_session_stat.finishing); break; } @@ -259,7 +310,7 @@ void __export ap_session_finished(struct ap_session *ses) ses->backup->storage->free(ses->backup); #endif - if (ap_shutdown && !ap_session_stat.starting && !ap_session_stat.active && !ap_session_stat.finishing) { + if (ap_shutdown && ap_session_stat_idle()) { if (shutdown_cb) shutdown_cb(); else @@ -292,19 +343,18 @@ void __export ap_session_terminate(struct ap_session *ses, int cause, int hard) } if (ses->state == AP_STATE_ACTIVE) - __sync_sub_and_fetch(&ap_session_stat.active, 1); + ap_session_stat_move(&ap_session_stat.active, &ap_session_stat.finishing); else - __sync_sub_and_fetch(&ap_session_stat.starting, 1); + ap_session_stat_move(&ap_session_stat.starting, &ap_session_stat.finishing); - __sync_add_and_fetch(&ap_session_stat.finishing, 1); ses->terminating = 1; ses->state = AP_STATE_FINISHING; log_ppp_debug("terminate\n"); + ap_session_read_stats(ses, NULL); if (ses->ctrl->terminate(ses, hard)) { ap_session_ifdown(ses); - ap_session_read_stats(ses, NULL); triton_event_fire(EV_SES_FINISHING, ses); @@ -326,7 +376,7 @@ int ap_shutdown_soft(void (*cb)(void), int term) pthread_rwlock_rdlock(&ses_lock); - if (!ap_session_stat.starting && !ap_session_stat.active && !ap_session_stat.finishing) { + if (ap_session_stat_idle()) { pthread_rwlock_unlock(&ses_lock); if (shutdown_cb) shutdown_cb(); diff --git a/accel-pppd/triton/md.c b/accel-pppd/triton/md.c index 9b7dd81a..374e49a5 100644 --- a/accel-pppd/triton/md.c +++ b/accel-pppd/triton/md.c @@ -87,7 +87,7 @@ static void *md_thread(void *arg) if (!h->pending) { list_add_tail(&h->entry2, &h->ctx->pending_handlers); h->pending = 1; - __sync_add_and_fetch(&triton_stat.md_handler_pending, 1); + triton_stat_md_handler_pending_inc(); r = triton_queue_ctx(h->ctx); } else r = 0; @@ -129,7 +129,7 @@ void __export triton_md_register_handler(struct triton_context_t *ctx, struct tr list_add_tail(&h->entry, &h->ctx->handlers); spin_unlock(&h->ctx->lock); - __sync_add_and_fetch(&triton_stat.md_handler_count, 1); + triton_stat_md_handler_count_inc(); } void __export triton_md_unregister_handler(struct triton_md_handler_t *ud, int c) @@ -148,7 +148,7 @@ void __export triton_md_unregister_handler(struct triton_md_handler_t *ud, int c list_del(&h->entry); if (h->pending) { list_del(&h->entry2); - __sync_sub_and_fetch(&triton_stat.md_handler_pending, 1); + triton_stat_md_handler_pending_dec(); } spin_unlock(&h->ctx->lock); @@ -158,7 +158,7 @@ void __export triton_md_unregister_handler(struct triton_md_handler_t *ud, int c ud->tpd = NULL; - __sync_sub_and_fetch(&triton_stat.md_handler_count, 1); + triton_stat_md_handler_count_dec(); } int __export triton_md_enable_handler(struct triton_md_handler_t *ud, int mode) diff --git a/accel-pppd/triton/mempool.c b/accel-pppd/triton/mempool.c index ea6d1e6d..a3c72dae 100644 --- a/accel-pppd/triton/mempool.c +++ b/accel-pppd/triton/mempool.c @@ -95,7 +95,7 @@ void __export *mempool_alloc(mempool_t *pool) { struct _mempool_t *p = (struct _mempool_t *)pool; struct _item_t *it; - uint32_t size = sizeof(*it) + p->size + 8; + size_t size = sizeof(*it) + p->size + 8; spin_lock(&p->lock); if (!list_empty(&p->items)) { @@ -104,7 +104,7 @@ void __export *mempool_alloc(mempool_t *pool) spin_unlock(&p->lock); --p->objects; - __sync_sub_and_fetch(&triton_stat.mempool_available, size); + triton_stat_mempool_available_sub(size); return it->ptr; } @@ -121,10 +121,10 @@ void __export *mempool_alloc(mempool_t *pool) it = (struct _item_t *)mmap_ptr; mmap_ptr += size; spin_unlock(&mmap_lock); - __sync_sub_and_fetch(&triton_stat.mempool_available, size); + triton_stat_mempool_available_sub(size); } else { it = _malloc(size); - __sync_add_and_fetch(&triton_stat.mempool_allocated, size); + triton_stat_mempool_allocated_add(size); } if (!it) { @@ -140,7 +140,7 @@ void __export mempool_free(void *ptr) { struct _item_t *it = container_of(ptr, typeof(*it), ptr); struct _mempool_t *p = it->owner; - uint32_t size = sizeof(*it) + it->owner->size + 8; + size_t size = sizeof(*it) + it->owner->size + 8; int need_free = 0; #ifdef MEMDEBUG @@ -184,9 +184,9 @@ void __export mempool_free(void *ptr) #else if (need_free) { _free(it); - __sync_sub_and_fetch(&triton_stat.mempool_allocated, size); + triton_stat_mempool_allocated_sub(size); } else - __sync_add_and_fetch(&triton_stat.mempool_available, size); + triton_stat_mempool_available_add(size); #endif } @@ -220,7 +220,7 @@ static void mempool_clean(void) { struct _mempool_t *p; struct _item_t *it; - uint32_t size; + size_t size; triton_log_error("mempool: clean"); @@ -238,8 +238,8 @@ static void mempool_clean(void) #endif list_del(&it->entry); _free(it); - __sync_sub_and_fetch(&triton_stat.mempool_allocated, size); - __sync_sub_and_fetch(&triton_stat.mempool_available, size); + triton_stat_mempool_allocated_sub(size); + triton_stat_mempool_available_sub(size); #ifdef VALGRIND } else break; @@ -257,7 +257,7 @@ static void sigclean(int num) static int mmap_grow(void) { - int size = sysconf(_SC_PAGESIZE) * (1 << PAGE_ORDER); + size_t size = sysconf(_SC_PAGESIZE) * (1 << PAGE_ORDER); uint8_t *ptr; if (mmap_endptr) { @@ -275,8 +275,8 @@ static int mmap_grow(void) mmap_endptr = ptr + size; - __sync_add_and_fetch(&triton_stat.mempool_allocated, size); - __sync_add_and_fetch(&triton_stat.mempool_available, size); + triton_stat_mempool_allocated_add(size); + triton_stat_mempool_available_add(size); return 0; oom: @@ -301,4 +301,3 @@ static void __init init(void) mmap_grow(); } - diff --git a/accel-pppd/triton/mempool.h b/accel-pppd/triton/mempool.h index 9ad2c370..c4f27588 100644 --- a/accel-pppd/triton/mempool.h +++ b/accel-pppd/triton/mempool.h @@ -3,16 +3,10 @@ #include <stdint.h> -struct mempool_stat_t -{ - uint32_t allocated; - uint32_t available; -}; typedef void * mempool_t; mempool_t *mempool_create(int size); mempool_t *mempool_create2(int size); -struct mempool_stat_t mempool_get_stat(void); #ifdef MEMDEBUG #include "memdebug.h" diff --git a/accel-pppd/triton/timer.c b/accel-pppd/triton/timer.c index 5b5d9535..ed23eb1d 100644 --- a/accel-pppd/triton/timer.c +++ b/accel-pppd/triton/timer.c @@ -95,7 +95,7 @@ void *timer_thread(void *arg) if (!t->pending) { list_add_tail(&t->entry2, &t->ctx->pending_timers); t->pending = 1; - __sync_add_and_fetch(&triton_stat.timer_pending, 1); + triton_stat_timer_pending_inc(); r = triton_queue_ctx(t->ctx); } else r = 0; @@ -167,7 +167,7 @@ int __export triton_timer_add(struct triton_context_t *ctx, struct triton_timer_ goto out_err; } - __sync_add_and_fetch(&triton_stat.timer_count, 1); + triton_stat_timer_count_inc(); return 0; @@ -206,7 +206,7 @@ void __export triton_timer_del(struct triton_timer_t *ud) list_del(&t->entry); if (t->pending) { list_del(&t->entry2); - __sync_sub_and_fetch(&triton_stat.timer_pending, 1); + triton_stat_timer_pending_dec(); } spin_unlock(&t->ctx->lock); @@ -216,6 +216,6 @@ void __export triton_timer_del(struct triton_timer_t *ud) ud->tpd = NULL; - __sync_sub_and_fetch(&triton_stat.timer_count, 1); + triton_stat_timer_count_dec(); } diff --git a/accel-pppd/triton/triton.c b/accel-pppd/triton/triton.c index 395a42df..105f810a 100644 --- a/accel-pppd/triton/triton.c +++ b/accel-pppd/triton/triton.c @@ -32,13 +32,15 @@ static LIST_HEAD(init_list); static int terminate; static int need_terminate; +/* 0 - idle, 1 - reload requested, 2 - reload running */ static int need_config_reload; -static void (*config_reload_notify)(int); +static void (*config_reload_notify)(int, void *); +static void *config_reload_arg; static mempool_t *ctx_pool; static mempool_t *call_pool; -struct triton_stat_t __export triton_stat; +static struct triton_stat_t triton_stat; static struct timeval ru_utime; static struct timeval ru_stime; @@ -57,20 +59,167 @@ static __thread void *thread_frame; #define log_debug2(fmt, ...) +void __export triton_stat_get(struct triton_stat_t *stat) +{ + stat->mempool_allocated = __atomic_load_n(&triton_stat.mempool_allocated, __ATOMIC_RELAXED); + stat->mempool_available = __atomic_load_n(&triton_stat.mempool_available, __ATOMIC_RELAXED); + stat->thread_count = __atomic_load_n(&triton_stat.thread_count, __ATOMIC_RELAXED); + stat->thread_active = __atomic_load_n(&triton_stat.thread_active, __ATOMIC_RELAXED); + stat->context_count = __atomic_load_n(&triton_stat.context_count, __ATOMIC_RELAXED); + stat->context_sleeping = __atomic_load_n(&triton_stat.context_sleeping, __ATOMIC_RELAXED); + stat->context_pending = __atomic_load_n(&triton_stat.context_pending, __ATOMIC_RELAXED); + stat->md_handler_count = __atomic_load_n(&triton_stat.md_handler_count, __ATOMIC_RELAXED); + stat->md_handler_pending = __atomic_load_n(&triton_stat.md_handler_pending, __ATOMIC_RELAXED); + stat->timer_count = __atomic_load_n(&triton_stat.timer_count, __ATOMIC_RELAXED); + stat->timer_pending = __atomic_load_n(&triton_stat.timer_pending, __ATOMIC_RELAXED); + stat->start_time = __atomic_load_n(&triton_stat.start_time, __ATOMIC_RELAXED); + stat->cpu = __atomic_load_n(&triton_stat.cpu, __ATOMIC_RELAXED); +} + +time_t __export triton_stat_start_time(void) +{ + return __atomic_load_n(&triton_stat.start_time, __ATOMIC_RELAXED); +} + +unsigned int __export triton_stat_cpu(void) +{ + return __atomic_load_n(&triton_stat.cpu, __ATOMIC_RELAXED); +} + +void triton_stat_mempool_allocated_add(uint64_t value) +{ + __atomic_add_fetch(&triton_stat.mempool_allocated, value, __ATOMIC_RELAXED); +} + +void triton_stat_mempool_allocated_sub(uint64_t value) +{ + __atomic_sub_fetch(&triton_stat.mempool_allocated, value, __ATOMIC_RELAXED); +} + +void triton_stat_mempool_available_add(uint64_t value) +{ + __atomic_add_fetch(&triton_stat.mempool_available, value, __ATOMIC_RELAXED); +} + +void triton_stat_mempool_available_sub(uint64_t value) +{ + __atomic_sub_fetch(&triton_stat.mempool_available, value, __ATOMIC_RELAXED); +} + +void triton_stat_thread_count_inc(void) +{ + __atomic_add_fetch(&triton_stat.thread_count, 1, __ATOMIC_RELAXED); +} + +void triton_stat_thread_active_inc(void) +{ + __atomic_add_fetch(&triton_stat.thread_active, 1, __ATOMIC_RELAXED); +} + +unsigned int triton_stat_thread_active_dec(void) +{ + return __atomic_sub_fetch(&triton_stat.thread_active, 1, __ATOMIC_RELAXED); +} + +static unsigned int triton_stat_thread_active(void) +{ + return __atomic_load_n(&triton_stat.thread_active, __ATOMIC_RELAXED); +} + +void triton_stat_context_count_inc(void) +{ + __atomic_add_fetch(&triton_stat.context_count, 1, __ATOMIC_RELAXED); +} + +unsigned int triton_stat_context_count_dec(void) +{ + return __atomic_sub_fetch(&triton_stat.context_count, 1, __ATOMIC_RELAXED); +} + +void triton_stat_context_sleeping_inc(void) +{ + __atomic_add_fetch(&triton_stat.context_sleeping, 1, __ATOMIC_RELAXED); +} + +void triton_stat_context_sleeping_dec(void) +{ + __atomic_sub_fetch(&triton_stat.context_sleeping, 1, __ATOMIC_RELAXED); +} + +void triton_stat_context_pending_inc(void) +{ + __atomic_add_fetch(&triton_stat.context_pending, 1, __ATOMIC_RELAXED); +} + +void triton_stat_context_pending_dec(void) +{ + __atomic_sub_fetch(&triton_stat.context_pending, 1, __ATOMIC_RELAXED); +} + +void triton_stat_md_handler_count_inc(void) +{ + __atomic_add_fetch(&triton_stat.md_handler_count, 1, __ATOMIC_RELAXED); +} + +void triton_stat_md_handler_count_dec(void) +{ + __atomic_sub_fetch(&triton_stat.md_handler_count, 1, __ATOMIC_RELAXED); +} + +void triton_stat_md_handler_pending_inc(void) +{ + __atomic_add_fetch(&triton_stat.md_handler_pending, 1, __ATOMIC_RELAXED); +} + +void triton_stat_md_handler_pending_dec(void) +{ + __atomic_sub_fetch(&triton_stat.md_handler_pending, 1, __ATOMIC_RELAXED); +} + +void triton_stat_timer_count_inc(void) +{ + __atomic_add_fetch(&triton_stat.timer_count, 1, __ATOMIC_RELAXED); +} + +void triton_stat_timer_count_dec(void) +{ + __atomic_sub_fetch(&triton_stat.timer_count, 1, __ATOMIC_RELAXED); +} + +void triton_stat_timer_pending_inc(void) +{ + __atomic_add_fetch(&triton_stat.timer_pending, 1, __ATOMIC_RELAXED); +} + +void triton_stat_timer_pending_dec(void) +{ + __atomic_sub_fetch(&triton_stat.timer_pending, 1, __ATOMIC_RELAXED); +} + +void triton_stat_set_cpu(unsigned int value) +{ + __atomic_store_n(&triton_stat.cpu, value, __ATOMIC_RELAXED); +} + +void triton_stat_set_start_time(time_t value) +{ + __atomic_store_n(&triton_stat.start_time, value, __ATOMIC_RELAXED); +} + void triton_thread_wakeup(struct _triton_thread_t *thread) { log_debug2("wake up thread %p\n", thread); pthread_kill(thread->thread, SIGUSR1); } -static void __config_reload(void (*notify)(int)) +static void __config_reload(void) { struct _triton_thread_t *t; int r; log_debug2("config_reload: enter\n"); r = conf_reload(NULL); - notify(r); + config_reload_notify(r, config_reload_arg); spin_lock(&threads_lock); need_config_reload = 0; @@ -146,7 +295,7 @@ static void* triton_thread(struct _triton_thread_t *thread) thread->ctx->thread = thread; thread->ctx->queued = 0; spin_unlock(&threads_lock); - __sync_sub_and_fetch(&triton_stat.context_pending, 1); + triton_stat_context_pending_dec(); } } else { log_debug2("thread: %p: sleeping\n", thread); @@ -154,9 +303,10 @@ static void* triton_thread(struct _triton_thread_t *thread) if (!terminate) list_add(&thread->entry2, &sleep_threads); - if (__sync_sub_and_fetch(&triton_stat.thread_active, 1) == 0 && need_config_reload) { + if (triton_stat_thread_active_dec() == 0 && need_config_reload == 1) { + need_config_reload = 2; spin_unlock(&threads_lock); - __config_reload(config_reload_notify); + __config_reload(); } else spin_unlock(&threads_lock); @@ -172,7 +322,7 @@ static void* triton_thread(struct _triton_thread_t *thread) //printf("thread %p: exit sigwait\n", thread); spin_lock(&threads_lock); - __sync_add_and_fetch(&triton_stat.thread_active, 1); + triton_stat_thread_active_inc(); if (!thread->ctx) { list_del(&thread->entry2); spin_unlock(&threads_lock); @@ -228,7 +378,7 @@ static void ctx_thread(struct _triton_context_t *ctx) list_del(&t->entry2); t->pending = 0; spin_unlock(&ctx->lock); - __sync_sub_and_fetch(&triton_stat.timer_pending, 1); + triton_stat_timer_pending_dec(); read(t->fd, &tt, sizeof(tt)); if (t->ud) t->ud->expire(t->ud); @@ -243,7 +393,7 @@ static void ctx_thread(struct _triton_context_t *ctx) h->trig_epoll_events = 0; spin_unlock(&ctx->lock); - __sync_sub_and_fetch(&triton_stat.md_handler_pending, 1); + triton_stat_md_handler_pending_dec(); h->armed = 0; @@ -320,8 +470,8 @@ struct _triton_thread_t *create_thread() while (pthread_create(&thread->thread, &attr, (void*(*)(void*))triton_thread, thread)) sleep(1); - __sync_add_and_fetch(&triton_stat.thread_count, 1); - __sync_add_and_fetch(&triton_stat.thread_active, 1); + triton_stat_thread_count_inc(); + triton_stat_thread_active_inc(); return thread; } @@ -340,7 +490,7 @@ int triton_queue_ctx(struct _triton_context_t *ctx) spin_unlock(&threads_lock); ctx->queued = 1; log_debug2("ctx %p: queued\n", ctx); - __sync_add_and_fetch(&triton_stat.context_pending, 1); + triton_stat_context_pending_inc(); return 0; } @@ -386,8 +536,8 @@ int __export triton_context_register(struct triton_context_t *ud, void *bf_arg) list_add_tail(&ctx->entry, &ctx_list); spin_unlock(&ctx_list_lock); - __sync_add_and_fetch(&triton_stat.context_sleeping, 1); - __sync_add_and_fetch(&triton_stat.context_count, 1); + triton_stat_context_sleeping_inc(); + triton_stat_context_count_inc(); return 0; } @@ -437,7 +587,7 @@ void __export triton_context_unregister(struct triton_context_t *ud) spin_lock(&ctx_list_lock); list_del(&ctx->entry); - if (__sync_sub_and_fetch(&triton_stat.context_count, 1) == 1) { + if (triton_stat_context_count_dec() == 1) { if (need_terminate) terminate = 1; } @@ -492,7 +642,7 @@ void __export triton_context_schedule() volatile struct _triton_context_t *ctx = (struct _triton_context_t *)this_ctx->tpd; log_debug2("ctx %p: enter schedule\n", ctx); - __sync_add_and_fetch(&triton_stat.context_sleeping, 1); + triton_stat_context_sleeping_inc(); ctx->uc = alloc_context(); @@ -509,7 +659,7 @@ void __export triton_context_schedule() spin_unlock(&threads_lock); _free(ctx->uc); ctx->uc = NULL; - __sync_sub_and_fetch(&triton_stat.context_sleeping, 1); + triton_stat_context_sleeping_dec(); log_debug2("ctx %p: exit schedule\n", ctx); } else { ctx->asleep = 1; @@ -527,7 +677,7 @@ void __export triton_context_wakeup(struct triton_context_t *ud) log_debug2("ctx %p: wakeup\n", ctx); if (ctx->init) { - __sync_sub_and_fetch(&triton_stat.context_sleeping, 1); + triton_stat_context_sleeping_dec(); spin_lock(&ctx->lock); ctx->init = 0; if (ctx->pending) @@ -610,7 +760,7 @@ void __export triton_collect_cpu_usage(void) clock_gettime(CLOCK_MONOTONIC, &ru_timestamp); ru_utime = rusage.ru_utime; ru_stime = rusage.ru_stime; - triton_stat.cpu = 0; + triton_stat_set_cpu(0); } } @@ -634,7 +784,7 @@ static void ru_update(struct triton_timer_t *t) val = (double)((rusage.ru_utime.tv_sec - ru_utime.tv_sec) * 1000000 + (rusage.ru_utime.tv_usec - ru_utime.tv_usec) + (rusage.ru_stime.tv_sec - ru_stime.tv_sec) * 1000000 + (rusage.ru_stime.tv_usec - ru_stime.tv_usec)) / dt * 100; - triton_stat.cpu = val; + triton_stat_set_cpu(val); ru_timestamp = ts; ru_utime = rusage.ru_utime; @@ -709,16 +859,25 @@ int __export triton_load_modules(const char *mod_sect) return 0; } -void __export triton_conf_reload(void (*notify)(int)) +int __export triton_conf_reload(void (*notify)(int, void *), void *arg) { spin_lock(&threads_lock); - need_config_reload = 1; + if (need_config_reload) { + spin_unlock(&threads_lock); + return -1; + } config_reload_notify = notify; - if (triton_stat.thread_active == 0) { + config_reload_arg = arg; + if (triton_stat_thread_active() == 0) { + need_config_reload = 2; spin_unlock(&threads_lock); - __config_reload(notify); - } else + __config_reload(); + } else { + need_config_reload = 1; spin_unlock(&threads_lock); + } + + return 0; } void __export triton_run() @@ -752,7 +911,7 @@ void __export triton_run() } clock_gettime(CLOCK_MONOTONIC, &ts); - triton_stat.start_time = ts.tv_sec; + triton_stat_set_start_time(ts.tv_sec); md_run(); timer_run(); diff --git a/accel-pppd/triton/triton.h b/accel-pppd/triton/triton.h index 79bbee1b..63dc9188 100644 --- a/accel-pppd/triton/triton.h +++ b/accel-pppd/triton/triton.h @@ -55,8 +55,8 @@ struct conf_sect_t struct triton_stat_t { - unsigned int mempool_allocated; - unsigned int mempool_available; + uint64_t mempool_allocated; + uint64_t mempool_available; unsigned int thread_count; unsigned int thread_active; unsigned int context_count; @@ -70,7 +70,9 @@ struct triton_stat_t unsigned int cpu; }; -extern struct triton_stat_t triton_stat; +void triton_stat_get(struct triton_stat_t *stat); +time_t triton_stat_start_time(void); +unsigned int triton_stat_cpu(void); int triton_context_register(struct triton_context_t *, void *arg); void triton_context_unregister(struct triton_context_t *); void triton_context_set_priority(struct triton_context_t *, int); @@ -102,7 +104,7 @@ void triton_event_fire(int ev_id, void *arg); struct conf_sect_t *conf_get_section(const char *name); char *conf_get_opt(const char *sect, const char *name); -void triton_conf_reload(void (*notify)(int)); +int triton_conf_reload(void (*notify)(int, void *), void *arg); void triton_collect_cpu_usage(void); void triton_stop_collect_cpu_usage(void); diff --git a/accel-pppd/triton/triton_p.h b/accel-pppd/triton/triton_p.h index bc39d626..7fa70b63 100644 --- a/accel-pppd/triton/triton_p.h +++ b/accel-pppd/triton/triton_p.h @@ -119,4 +119,28 @@ void triton_log_debug(const char *fmt, ...) __attribute__((format(gnu_printf, 1, int load_modules(const char *name); void triton_context_release(struct _triton_context_t *ctx); +void triton_stat_mempool_allocated_add(uint64_t value); +void triton_stat_mempool_allocated_sub(uint64_t value); +void triton_stat_mempool_available_add(uint64_t value); +void triton_stat_mempool_available_sub(uint64_t value); +void triton_stat_thread_count_inc(void); +void triton_stat_thread_active_inc(void); +unsigned int triton_stat_thread_active_dec(void); +void triton_stat_context_count_inc(void); +unsigned int triton_stat_context_count_dec(void); +void triton_stat_context_sleeping_inc(void); +void triton_stat_context_sleeping_dec(void); +void triton_stat_context_pending_inc(void); +void triton_stat_context_pending_dec(void); +void triton_stat_md_handler_count_inc(void); +void triton_stat_md_handler_count_dec(void); +void triton_stat_md_handler_pending_inc(void); +void triton_stat_md_handler_pending_dec(void); +void triton_stat_timer_count_inc(void); +void triton_stat_timer_count_dec(void); +void triton_stat_timer_pending_inc(void); +void triton_stat_timer_pending_dec(void); +void triton_stat_set_cpu(unsigned int value); +void triton_stat_set_start_time(time_t value); + #endif diff --git a/accel-pppd/utils.c b/accel-pppd/utils.c index 018b6efa..f92ebe19 100644 --- a/accel-pppd/utils.c +++ b/accel-pppd/utils.c @@ -347,3 +347,14 @@ int __export u_randbuf(void *buf, size_t buf_len, int *err) return 0; } + +void __export u_strstrip(char *str, char c) +{ + char *src = str, *dst = str; + while (*src) { + if (*src != c) + *dst++ = *src; + src++; + } + *dst = '\0'; +} diff --git a/accel-pppd/utils.h b/accel-pppd/utils.h index 06859a6b..aad4025f 100644 --- a/accel-pppd/utils.h +++ b/accel-pppd/utils.h @@ -24,6 +24,7 @@ size_t u_parse_ip6cidr(const char *str, struct in6_addr *netp, uint8_t *plen); size_t u_parse_ip4cidr(const char *str, struct in_addr *netp, uint8_t *plen); size_t u_parse_ip4range(const char *str, struct in_addr *base_ip, uint8_t *max); +void u_strstrip(char *str, char c); int u_randbuf(void *buf, size_t buf_len, int *err); #endif diff --git a/cmake/cpack.cmake b/cmake/cpack.cmake index 3dfc2750..b0c4823d 100644 --- a/cmake/cpack.cmake +++ b/cmake/cpack.cmake @@ -1,6 +1,6 @@ INCLUDE(InstallRequiredSystemLibraries) -string(REPLACE "." ";" VERSION_LIST ${ACCEL_PPP_VERSION}) +string(REPLACE "." ";" VERSION_LIST "${ACCEL_PPP_VERSION}") # Verify if VERSION_LIST has 3 elements # If not assign dummy variables @@ -17,76 +17,56 @@ SET(CPACK_PACKAGE_CONTACT "Dmitry Kozlov <xeb@mail.ru>") SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "PPtP/L2TP/PPPoE/SSTP server for Linux") SET(CPACK_PACKAGE_VENDOR "Dmitry Kozlov") -SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") +SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") -IF(CPACK_TYPE STREQUAL Debian5) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.7), libssl0.9.8 (>= 0.9.8), libpcre3 (>= 7.6)") - INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) -ENDIF(CPACK_TYPE STREQUAL Debian5) - -IF(CPACK_TYPE STREQUAL Debian6) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.11.2), libssl0.9.8 (>= 0.9.8), libpcre3 (>= 8.02)") - INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) -ENDIF(CPACK_TYPE STREQUAL Debian6) - -IF(CPACK_TYPE STREQUAL Debian7) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.13), libssl1.0.0 (>= 1.0.0), libpcre3 (>= 8.30)") - INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) -ENDIF(CPACK_TYPE STREQUAL Debian7) - -IF(CPACK_TYPE STREQUAL Debian8) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.19), libssl1.0.0 (>= 1.0.1k), libpcre3 (>= 8.35)") - INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) -ENDIF(CPACK_TYPE STREQUAL Debian8) - IF(CPACK_TYPE STREQUAL Debian9) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.24), libssl1.0.2 (>= 1.0.2l), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.24), libssl1.0.2 (>= 1.0.2l), libpcre2-8-0 (>= 10.22)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Debian9) IF(CPACK_TYPE STREQUAL Debian10) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28), libssl1.1 (>= 1.1.1c), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.28), libssl1.1 (>= 1.1.1c), libpcre2-8-0 (>= 10.32)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Debian10) IF(CPACK_TYPE STREQUAL Debian11) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.31), libssl1.1 (>= 1.1.1k), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.31), libssl1.1 (>= 1.1.1k), libpcre2-8-0 (>= 10.36)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Debian11) IF(CPACK_TYPE STREQUAL Debian12) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.34), libssl3 (>= 3.0.5), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.34), libssl3 (>= 3.0.5), libpcre2-8-0 (>= 10.42)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Debian12) IF(CPACK_TYPE STREQUAL Debian13) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.37), libssl3 (>= 3.0.9), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.37), libssl3 (>= 3.0.9), libpcre2-8-0 (>= 10.42)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Debian13) IF(CPACK_TYPE STREQUAL Ubuntu16) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.23), libssl1.0.0 (>= 1.0.0), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.23), libssl1.0.0 (>= 1.0.0), libpcre2-8-0 (>= 10.21)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Ubuntu16) IF(CPACK_TYPE STREQUAL Ubuntu18) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.24), libssl1.0.0 (>= 1.0.2n), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.24), libssl1.0.0 (>= 1.0.2n), libpcre2-8-0 (>= 10.31)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Ubuntu18) IF(CPACK_TYPE STREQUAL Ubuntu20) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.31), libssl1.1 (>= 1.1.1d), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.31), libssl1.1 (>= 1.1.1d), libpcre2-8-0 (>= 10.34)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Ubuntu20) IF(CPACK_TYPE STREQUAL Ubuntu22) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.35), libssl3 (>= 3.0.2), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.35), libssl3 (>= 3.0.2), libpcre2-8-0 (>= 10.39)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Ubuntu22) IF(CPACK_TYPE STREQUAL Ubuntu24) - SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.35), libssl3 (>= 3.0.2), libpcre3 (>= 8.39)") + SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.35), libssl3 (>= 3.0.2), libpcre2-8-0 (>= 10.42)") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/debian/debian.cmake) ENDIF(CPACK_TYPE STREQUAL Ubuntu24) @@ -94,7 +74,7 @@ IF(CPACK_TYPE STREQUAL Centos7) SET(CPACK_RPM_PACKAGE_LICENSE "GPL") SET(CPACK_RPM_PACKAGE_URL "http://accel-ppp.org") SET(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/sbin") - SET(CPACK_RPM_PACKAGE_REQUIRES "glibc >= 2.17, openssl-libs >= 1.0.2k, pcre >= 8.32") + SET(CPACK_RPM_PACKAGE_REQUIRES "glibc >= 2.17, openssl-libs >= 1.0.2k, pcre2 >= 10.23") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/centos/centos.cmake) ENDIF() @@ -102,7 +82,7 @@ IF(CPACK_TYPE STREQUAL Centos8) SET(CPACK_RPM_PACKAGE_LICENSE "GPL") SET(CPACK_RPM_PACKAGE_URL "http://accel-ppp.org") SET(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/sbin") - SET(CPACK_RPM_PACKAGE_REQUIRES "glibc >= 2.28, openssl-libs >= 1.1.1, pcre >= 8.42") + SET(CPACK_RPM_PACKAGE_REQUIRES "glibc >= 2.28, openssl-libs >= 1.1.1, pcre2 >= 10.32") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/centos/centos.cmake) ENDIF() @@ -110,7 +90,7 @@ IF(CPACK_TYPE STREQUAL Centos9) SET(CPACK_RPM_PACKAGE_LICENSE "GPL") SET(CPACK_RPM_PACKAGE_URL "http://accel-ppp.org") SET(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/sbin") - SET(CPACK_RPM_PACKAGE_REQUIRES "glibc >= 2.34, openssl-libs >= 3.0.1, pcre >= 8.44") + SET(CPACK_RPM_PACKAGE_REQUIRES "glibc >= 2.34, openssl-libs >= 3.0.1, pcre2 >= 10.40") INCLUDE(${CMAKE_HOME_DIRECTORY}/cmake/centos/centos.cmake) ENDIF() diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt deleted file mode 100644 index 3e24a64e..00000000 --- a/crypto/CMakeLists.txt +++ /dev/null @@ -1,25 +0,0 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -IF (CRYPTO STREQUAL INTERNAL OR CRYPTO STREQUAL TOMCRYPT) - -SET(sources crypto.c) - -IF (CRYPTO STREQUAL INTERNAL) - SET(sources - ${sources} - crypto.c - md4.c - md5.c - sha1.c - des.c - ) -ENDIF(CRYPTO STREQUAL INTERNAL) - -ADD_LIBRARY(internal-crypto SHARED ${sources}) -IF (CRYPTO STREQUAL TOMCRYPT) - TARGET_LINK_LIBRARIES(internal-crypto tomcrypt) -ENDIF(CRYPTO STREQUAL TOMCRYPT) - -INSTALL(TARGETS internal-crypto LIBRARY DESTINATION lib${LIB_SUFFIX}/accel-ppp ) - -ENDIF(CRYPTO STREQUAL INTERNAL OR CRYPTO STREQUAL TOMCRYPT) diff --git a/crypto/crypto.c b/crypto/crypto.c deleted file mode 100644 index 634c0831..00000000 --- a/crypto/crypto.c +++ /dev/null @@ -1,121 +0,0 @@ -#include <unistd.h> -#include <fcntl.h> - -#include "crypto.h" - -#ifdef LTC_DES - -static int urandom_fd; - -static const unsigned char odd_parity[256] = { - 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, 14, - 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, 31, 31, - 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, 44, 47, 47, - 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, 61, 61, 62, 62, - 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, 74, 76, 76, 79, 79, - 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, 91, 91, 93, 93, 94, 94, - 97, 97, 98, 98,100,100,103,103,104,104,107,107,109,109,110,110, - 112,112,115,115,117,117,118,118,121,121,122,122,124,124,127,127, - 128,128,131,131,133,133,134,134,137,137,138,138,140,140,143,143, - 145,145,146,146,148,148,151,151,152,152,155,155,157,157,158,158, - 161,161,162,162,164,164,167,167,168,168,171,171,173,173,174,174, - 176,176,179,179,181,181,182,182,185,185,186,186,188,188,191,191, - 193,193,194,194,196,196,199,199,200,200,203,203,205,205,206,206, - 208,208,211,211,213,213,214,214,217,217,218,218,220,220,223,223, - 224,224,227,227,229,229,230,230,233,233,234,234,236,236,239,239, - 241,241,242,242,244,244,247,247,248,248,251,251,253,253,254,254 -}; - -void DES_set_odd_parity(DES_cblock *key) -{ - unsigned int i; - - for (i = 0; i < sizeof(DES_cblock); i++) - (*key)[i] = odd_parity[(*key)[i]]; -} - -int DES_check_key_parity(const_DES_cblock *key) -{ - unsigned int i; - - for (i = 0; i < sizeof(DES_cblock); i++) { - if ((*key)[i] != odd_parity[(*key)[i]]) - return 0; - } - - return 1; -} - -static const DES_cblock weak_keys[] = { - /* weak keys */ - {0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01}, - {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE}, - {0x1F,0x1F,0x1F,0x1F,0x0E,0x0E,0x0E,0x0E}, - {0xE0,0xE0,0xE0,0xE0,0xF1,0xF1,0xF1,0xF1}, - /* semi-weak keys */ - {0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE}, - {0xFE,0x01,0xFE,0x01,0xFE,0x01,0xFE,0x01}, - {0x1F,0xE0,0x1F,0xE0,0x0E,0xF1,0x0E,0xF1}, - {0xE0,0x1F,0xE0,0x1F,0xF1,0x0E,0xF1,0x0E}, - {0x01,0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1}, - {0xE0,0x01,0xE0,0x01,0xF1,0x01,0xF1,0x01}, - {0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E,0xFE}, - {0xFE,0x1F,0xFE,0x1F,0xFE,0x0E,0xFE,0x0E}, - {0x01,0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E}, - {0x1F,0x01,0x1F,0x01,0x0E,0x01,0x0E,0x01}, - {0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1,0xFE}, - {0xFE,0xE0,0xFE,0xE0,0xFE,0xF1,0xFE,0xF1} -}; - -int DES_is_weak_key(const_DES_cblock *key) -{ - int i; - - for (i = 0; i < sizeof(weak_keys); i++) - if (!memcmp(weak_keys[i], key, sizeof(DES_cblock))) - return 1; - - return 0; -} - -int DES_set_key_checked(const_DES_cblock *key, DES_key_schedule *schedule) -{ - if (!DES_check_key_parity(key)) - return -1; - - if (DES_is_weak_key(key)) - return -2; - - return des_setup((const unsigned char *)key, 8, 0, schedule); -} - -int DES_random_key(DES_cblock *ret) -{ - while (1) { - read(urandom_fd, ret, sizeof(DES_cblock)); - if (DES_is_weak_key(ret)) - continue; - break; - } - - DES_set_odd_parity(ret); - - return 0; -} - -void DES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks, int enc) -{ - if (enc == DES_ENCRYPT) - des_ecb_encrypt((const unsigned char *) input, (unsigned char *) output, ks); - else - if (enc == DES_DECRYPT) - des_ecb_decrypt((const unsigned char *) input, (unsigned char *) output, ks); - des_done(ks); -} - -static void __attribute__((constructor)) init(void) -{ - urandom_fd = open("/dev/urandom", O_RDONLY); - fcntl(urandom_fd, F_SETFD, fcntl(urandom_fd, F_GETFD) | FD_CLOEXEC); -} -#endif diff --git a/crypto/crypto.h b/crypto/crypto.h deleted file mode 100644 index 9e2e8401..00000000 --- a/crypto/crypto.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef __CRYPTO_H -#define __CRYPTO_H - -#ifdef CRYPTO_OPENSSL - -#include <openssl/md4.h> -#include <openssl/md5.h> -#include <openssl/sha.h> -#include <openssl/des.h> -#include <openssl/evp.h> - -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined (LIBRESSL_VERSION_NUMBER) -#define EVP_MD_CTX_new EVP_MD_CTX_create -#define EVP_MD_CTX_free EVP_MD_CTX_destroy -#endif -#else - -#ifdef CRYPTO_TOMCRYPT -#include <tomcrypt.h> -#else -#include "tomcrypt.h" -#endif - -typedef hash_state MD4_CTX; -#define MD4_DIGEST_LENGTH 16 -#define MD4_Init(c) md4_init(c) -#define MD4_Update(c, data, len) md4_process(c, (const unsigned char *)(data), (unsigned long)(len)) -#define MD4_Final(md, c) md4_done(c, (unsigned char*)(md)) - -typedef hash_state MD5_CTX; -#define MD5_DIGEST_LENGTH 16 -#define MD5_Init(c) md5_init(c) -#define MD5_Update(c, data, len) md5_process(c, (const unsigned char *)(data), (unsigned long)(len)) -#define MD5_Final(md, c) md5_done(c, (unsigned char*)(md)) - -typedef hash_state SHA_CTX; -#define SHA_DIGEST_LENGTH 20 -#define SHA1_Init(c) sha1_init(c) -#define SHA1_Update(c, data, len) sha1_process(c, (const unsigned char *)(data), (unsigned long)(len)) -#define SHA1_Final(md, c) sha1_done(c, (unsigned char*)(md)) - -typedef unsigned char DES_cblock[8]; -typedef unsigned char const_DES_cblock[8]; -#define DES_key_schedule symmetric_key -#define DES_ENCRYPT 1 -#define DES_DECRYPT 0 -#define DES_set_key(key, schedule) des_setup((const unsigned char *)key, 8, 0, schedule) - -int DES_set_key_checked(const_DES_cblock *key, DES_key_schedule *schedule); -int DES_random_key(DES_cblock *ret); -void DES_ecb_encrypt(const_DES_cblock *input, DES_cblock *output, DES_key_schedule *ks, int enc); - -#endif - -#endif diff --git a/crypto/des.c b/crypto/des.c deleted file mode 100644 index d6fe6966..00000000 --- a/crypto/des.c +++ /dev/null @@ -1,1914 +0,0 @@ -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org - */ -#include "tomcrypt.h" - -/** - @file des.c - LTC_DES code submitted by Dobes Vandermeer -*/ - -#ifdef LTC_DES - -#define EN0 0 -#define DE1 1 - -const struct ltc_cipher_descriptor des_desc = -{ - "des", - 13, - 8, 8, 8, 16, - &des_setup, - &des_ecb_encrypt, - &des_ecb_decrypt, - &des_test, - &des_done, - &des_keysize, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; - -#ifdef LTC_DES3 -const struct ltc_cipher_descriptor des3_desc = -{ - "3des", - 14, - 24, 24, 8, 16, - &des3_setup, - &des3_ecb_encrypt, - &des3_ecb_decrypt, - &des3_test, - &des3_done, - &des3_keysize, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; -#endif - -static const ulong32 bytebit[8] = -{ - 0200, 0100, 040, 020, 010, 04, 02, 01 -}; - -static const ulong32 bigbyte[24] = -{ - 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL, - 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL, - 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL, - 0x800UL, 0x400UL, 0x200UL, 0x100UL, - 0x80UL, 0x40UL, 0x20UL, 0x10UL, - 0x8UL, 0x4UL, 0x2UL, 0x1L -}; - -/* Use the key schedule specific in the standard (ANSI X3.92-1981) */ - -static const unsigned char pc1[56] = { - 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17, - 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, - 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, - 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3 -}; - -static const unsigned char totrot[16] = { - 1, 2, 4, 6, - 8, 10, 12, 14, - 15, 17, 19, 21, - 23, 25, 27, 28 -}; - -static const unsigned char pc2[48] = { - 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9, - 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1, - 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47, - 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 -}; - - -static const ulong32 SP1[64] = -{ - 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL, - 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL, - 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL, - 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL, - 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL, - 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL, - 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL, - 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL, - 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL, - 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL, - 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL, - 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL, - 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL, - 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL, - 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL, - 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL -}; - -static const ulong32 SP2[64] = -{ - 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL, - 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL, - 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL, - 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL, - 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL, - 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL, - 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL, - 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL, - 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL, - 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL, - 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL, - 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL, - 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL, - 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL, - 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL, - 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL -}; - -static const ulong32 SP3[64] = -{ - 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL, - 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL, - 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL, - 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL, - 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL, - 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL, - 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL, - 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL, - 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL, - 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL, - 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL, - 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL, - 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL, - 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL, - 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL, - 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL -}; - -static const ulong32 SP4[64] = -{ - 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, - 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL, - 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL, - 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL, - 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL, - 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL, - 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL, - 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL, - 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL, - 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL, - 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL, - 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL, - 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL, - 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL, - 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL, - 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL -}; - -static const ulong32 SP5[64] = -{ - 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL, - 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL, - 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL, - 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL, - 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL, - 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL, - 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL, - 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL, - 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL, - 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL, - 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL, - 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL, - 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL, - 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL, - 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL, - 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL -}; - -static const ulong32 SP6[64] = -{ - 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL, - 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL, - 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL, - 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, - 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL, - 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL, - 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL, - 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL, - 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL, - 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL, - 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL, - 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL, - 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL, - 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL, - 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL, - 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL -}; - -static const ulong32 SP7[64] = -{ - 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL, - 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL, - 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL, - 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL, - 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL, - 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL, - 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL, - 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL, - 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL, - 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL, - 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL, - 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL, - 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL, - 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL, - 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL, - 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL -}; - -static const ulong32 SP8[64] = -{ - 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL, - 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL, - 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL, - 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL, - 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL, - 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL, - 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL, - 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL, - 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL, - 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL, - 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL, - 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL, - 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL, - 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL, - 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL, - 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL -}; - -#ifndef LTC_SMALL_CODE - -static const ulong64 des_ip[8][256] = { - -{ CONST64(0x0000000000000000), CONST64(0x0000001000000000), CONST64(0x0000000000000010), CONST64(0x0000001000000010), - CONST64(0x0000100000000000), CONST64(0x0000101000000000), CONST64(0x0000100000000010), CONST64(0x0000101000000010), - CONST64(0x0000000000001000), CONST64(0x0000001000001000), CONST64(0x0000000000001010), CONST64(0x0000001000001010), - CONST64(0x0000100000001000), CONST64(0x0000101000001000), CONST64(0x0000100000001010), CONST64(0x0000101000001010), - CONST64(0x0010000000000000), CONST64(0x0010001000000000), CONST64(0x0010000000000010), CONST64(0x0010001000000010), - CONST64(0x0010100000000000), CONST64(0x0010101000000000), CONST64(0x0010100000000010), CONST64(0x0010101000000010), - CONST64(0x0010000000001000), CONST64(0x0010001000001000), CONST64(0x0010000000001010), CONST64(0x0010001000001010), - CONST64(0x0010100000001000), CONST64(0x0010101000001000), CONST64(0x0010100000001010), CONST64(0x0010101000001010), - CONST64(0x0000000000100000), CONST64(0x0000001000100000), CONST64(0x0000000000100010), CONST64(0x0000001000100010), - CONST64(0x0000100000100000), CONST64(0x0000101000100000), CONST64(0x0000100000100010), CONST64(0x0000101000100010), - CONST64(0x0000000000101000), CONST64(0x0000001000101000), CONST64(0x0000000000101010), CONST64(0x0000001000101010), - CONST64(0x0000100000101000), CONST64(0x0000101000101000), CONST64(0x0000100000101010), CONST64(0x0000101000101010), - CONST64(0x0010000000100000), CONST64(0x0010001000100000), CONST64(0x0010000000100010), CONST64(0x0010001000100010), - CONST64(0x0010100000100000), CONST64(0x0010101000100000), CONST64(0x0010100000100010), CONST64(0x0010101000100010), - CONST64(0x0010000000101000), CONST64(0x0010001000101000), CONST64(0x0010000000101010), CONST64(0x0010001000101010), - CONST64(0x0010100000101000), CONST64(0x0010101000101000), CONST64(0x0010100000101010), CONST64(0x0010101000101010), - CONST64(0x1000000000000000), CONST64(0x1000001000000000), CONST64(0x1000000000000010), CONST64(0x1000001000000010), - CONST64(0x1000100000000000), CONST64(0x1000101000000000), CONST64(0x1000100000000010), CONST64(0x1000101000000010), - CONST64(0x1000000000001000), CONST64(0x1000001000001000), CONST64(0x1000000000001010), CONST64(0x1000001000001010), - CONST64(0x1000100000001000), CONST64(0x1000101000001000), CONST64(0x1000100000001010), CONST64(0x1000101000001010), - CONST64(0x1010000000000000), CONST64(0x1010001000000000), CONST64(0x1010000000000010), CONST64(0x1010001000000010), - CONST64(0x1010100000000000), CONST64(0x1010101000000000), CONST64(0x1010100000000010), CONST64(0x1010101000000010), - CONST64(0x1010000000001000), CONST64(0x1010001000001000), CONST64(0x1010000000001010), CONST64(0x1010001000001010), - CONST64(0x1010100000001000), CONST64(0x1010101000001000), CONST64(0x1010100000001010), CONST64(0x1010101000001010), - CONST64(0x1000000000100000), CONST64(0x1000001000100000), CONST64(0x1000000000100010), CONST64(0x1000001000100010), - CONST64(0x1000100000100000), CONST64(0x1000101000100000), CONST64(0x1000100000100010), CONST64(0x1000101000100010), - CONST64(0x1000000000101000), CONST64(0x1000001000101000), CONST64(0x1000000000101010), CONST64(0x1000001000101010), - CONST64(0x1000100000101000), CONST64(0x1000101000101000), CONST64(0x1000100000101010), CONST64(0x1000101000101010), - CONST64(0x1010000000100000), CONST64(0x1010001000100000), CONST64(0x1010000000100010), CONST64(0x1010001000100010), - CONST64(0x1010100000100000), CONST64(0x1010101000100000), CONST64(0x1010100000100010), CONST64(0x1010101000100010), - CONST64(0x1010000000101000), CONST64(0x1010001000101000), CONST64(0x1010000000101010), CONST64(0x1010001000101010), - CONST64(0x1010100000101000), CONST64(0x1010101000101000), CONST64(0x1010100000101010), CONST64(0x1010101000101010), - CONST64(0x0000000010000000), CONST64(0x0000001010000000), CONST64(0x0000000010000010), CONST64(0x0000001010000010), - CONST64(0x0000100010000000), CONST64(0x0000101010000000), CONST64(0x0000100010000010), CONST64(0x0000101010000010), - CONST64(0x0000000010001000), CONST64(0x0000001010001000), CONST64(0x0000000010001010), CONST64(0x0000001010001010), - CONST64(0x0000100010001000), CONST64(0x0000101010001000), CONST64(0x0000100010001010), CONST64(0x0000101010001010), - CONST64(0x0010000010000000), CONST64(0x0010001010000000), CONST64(0x0010000010000010), CONST64(0x0010001010000010), - CONST64(0x0010100010000000), CONST64(0x0010101010000000), CONST64(0x0010100010000010), CONST64(0x0010101010000010), - CONST64(0x0010000010001000), CONST64(0x0010001010001000), CONST64(0x0010000010001010), CONST64(0x0010001010001010), - CONST64(0x0010100010001000), CONST64(0x0010101010001000), CONST64(0x0010100010001010), CONST64(0x0010101010001010), - CONST64(0x0000000010100000), CONST64(0x0000001010100000), CONST64(0x0000000010100010), CONST64(0x0000001010100010), - CONST64(0x0000100010100000), CONST64(0x0000101010100000), CONST64(0x0000100010100010), CONST64(0x0000101010100010), - CONST64(0x0000000010101000), CONST64(0x0000001010101000), CONST64(0x0000000010101010), CONST64(0x0000001010101010), - CONST64(0x0000100010101000), CONST64(0x0000101010101000), CONST64(0x0000100010101010), CONST64(0x0000101010101010), - CONST64(0x0010000010100000), CONST64(0x0010001010100000), CONST64(0x0010000010100010), CONST64(0x0010001010100010), - CONST64(0x0010100010100000), CONST64(0x0010101010100000), CONST64(0x0010100010100010), CONST64(0x0010101010100010), - CONST64(0x0010000010101000), CONST64(0x0010001010101000), CONST64(0x0010000010101010), CONST64(0x0010001010101010), - CONST64(0x0010100010101000), CONST64(0x0010101010101000), CONST64(0x0010100010101010), CONST64(0x0010101010101010), - CONST64(0x1000000010000000), CONST64(0x1000001010000000), CONST64(0x1000000010000010), CONST64(0x1000001010000010), - CONST64(0x1000100010000000), CONST64(0x1000101010000000), CONST64(0x1000100010000010), CONST64(0x1000101010000010), - CONST64(0x1000000010001000), CONST64(0x1000001010001000), CONST64(0x1000000010001010), CONST64(0x1000001010001010), - CONST64(0x1000100010001000), CONST64(0x1000101010001000), CONST64(0x1000100010001010), CONST64(0x1000101010001010), - CONST64(0x1010000010000000), CONST64(0x1010001010000000), CONST64(0x1010000010000010), CONST64(0x1010001010000010), - CONST64(0x1010100010000000), CONST64(0x1010101010000000), CONST64(0x1010100010000010), CONST64(0x1010101010000010), - CONST64(0x1010000010001000), CONST64(0x1010001010001000), CONST64(0x1010000010001010), CONST64(0x1010001010001010), - CONST64(0x1010100010001000), CONST64(0x1010101010001000), CONST64(0x1010100010001010), CONST64(0x1010101010001010), - CONST64(0x1000000010100000), CONST64(0x1000001010100000), CONST64(0x1000000010100010), CONST64(0x1000001010100010), - CONST64(0x1000100010100000), CONST64(0x1000101010100000), CONST64(0x1000100010100010), CONST64(0x1000101010100010), - CONST64(0x1000000010101000), CONST64(0x1000001010101000), CONST64(0x1000000010101010), CONST64(0x1000001010101010), - CONST64(0x1000100010101000), CONST64(0x1000101010101000), CONST64(0x1000100010101010), CONST64(0x1000101010101010), - CONST64(0x1010000010100000), CONST64(0x1010001010100000), CONST64(0x1010000010100010), CONST64(0x1010001010100010), - CONST64(0x1010100010100000), CONST64(0x1010101010100000), CONST64(0x1010100010100010), CONST64(0x1010101010100010), - CONST64(0x1010000010101000), CONST64(0x1010001010101000), CONST64(0x1010000010101010), CONST64(0x1010001010101010), - CONST64(0x1010100010101000), CONST64(0x1010101010101000), CONST64(0x1010100010101010), CONST64(0x1010101010101010) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000000800000000), CONST64(0x0000000000000008), CONST64(0x0000000800000008), - CONST64(0x0000080000000000), CONST64(0x0000080800000000), CONST64(0x0000080000000008), CONST64(0x0000080800000008), - CONST64(0x0000000000000800), CONST64(0x0000000800000800), CONST64(0x0000000000000808), CONST64(0x0000000800000808), - CONST64(0x0000080000000800), CONST64(0x0000080800000800), CONST64(0x0000080000000808), CONST64(0x0000080800000808), - CONST64(0x0008000000000000), CONST64(0x0008000800000000), CONST64(0x0008000000000008), CONST64(0x0008000800000008), - CONST64(0x0008080000000000), CONST64(0x0008080800000000), CONST64(0x0008080000000008), CONST64(0x0008080800000008), - CONST64(0x0008000000000800), CONST64(0x0008000800000800), CONST64(0x0008000000000808), CONST64(0x0008000800000808), - CONST64(0x0008080000000800), CONST64(0x0008080800000800), CONST64(0x0008080000000808), CONST64(0x0008080800000808), - CONST64(0x0000000000080000), CONST64(0x0000000800080000), CONST64(0x0000000000080008), CONST64(0x0000000800080008), - CONST64(0x0000080000080000), CONST64(0x0000080800080000), CONST64(0x0000080000080008), CONST64(0x0000080800080008), - CONST64(0x0000000000080800), CONST64(0x0000000800080800), CONST64(0x0000000000080808), CONST64(0x0000000800080808), - CONST64(0x0000080000080800), CONST64(0x0000080800080800), CONST64(0x0000080000080808), CONST64(0x0000080800080808), - CONST64(0x0008000000080000), CONST64(0x0008000800080000), CONST64(0x0008000000080008), CONST64(0x0008000800080008), - CONST64(0x0008080000080000), CONST64(0x0008080800080000), CONST64(0x0008080000080008), CONST64(0x0008080800080008), - CONST64(0x0008000000080800), CONST64(0x0008000800080800), CONST64(0x0008000000080808), CONST64(0x0008000800080808), - CONST64(0x0008080000080800), CONST64(0x0008080800080800), CONST64(0x0008080000080808), CONST64(0x0008080800080808), - CONST64(0x0800000000000000), CONST64(0x0800000800000000), CONST64(0x0800000000000008), CONST64(0x0800000800000008), - CONST64(0x0800080000000000), CONST64(0x0800080800000000), CONST64(0x0800080000000008), CONST64(0x0800080800000008), - CONST64(0x0800000000000800), CONST64(0x0800000800000800), CONST64(0x0800000000000808), CONST64(0x0800000800000808), - CONST64(0x0800080000000800), CONST64(0x0800080800000800), CONST64(0x0800080000000808), CONST64(0x0800080800000808), - CONST64(0x0808000000000000), CONST64(0x0808000800000000), CONST64(0x0808000000000008), CONST64(0x0808000800000008), - CONST64(0x0808080000000000), CONST64(0x0808080800000000), CONST64(0x0808080000000008), CONST64(0x0808080800000008), - CONST64(0x0808000000000800), CONST64(0x0808000800000800), CONST64(0x0808000000000808), CONST64(0x0808000800000808), - CONST64(0x0808080000000800), CONST64(0x0808080800000800), CONST64(0x0808080000000808), CONST64(0x0808080800000808), - CONST64(0x0800000000080000), CONST64(0x0800000800080000), CONST64(0x0800000000080008), CONST64(0x0800000800080008), - CONST64(0x0800080000080000), CONST64(0x0800080800080000), CONST64(0x0800080000080008), CONST64(0x0800080800080008), - CONST64(0x0800000000080800), CONST64(0x0800000800080800), CONST64(0x0800000000080808), CONST64(0x0800000800080808), - CONST64(0x0800080000080800), CONST64(0x0800080800080800), CONST64(0x0800080000080808), CONST64(0x0800080800080808), - CONST64(0x0808000000080000), CONST64(0x0808000800080000), CONST64(0x0808000000080008), CONST64(0x0808000800080008), - CONST64(0x0808080000080000), CONST64(0x0808080800080000), CONST64(0x0808080000080008), CONST64(0x0808080800080008), - CONST64(0x0808000000080800), CONST64(0x0808000800080800), CONST64(0x0808000000080808), CONST64(0x0808000800080808), - CONST64(0x0808080000080800), CONST64(0x0808080800080800), CONST64(0x0808080000080808), CONST64(0x0808080800080808), - CONST64(0x0000000008000000), CONST64(0x0000000808000000), CONST64(0x0000000008000008), CONST64(0x0000000808000008), - CONST64(0x0000080008000000), CONST64(0x0000080808000000), CONST64(0x0000080008000008), CONST64(0x0000080808000008), - CONST64(0x0000000008000800), CONST64(0x0000000808000800), CONST64(0x0000000008000808), CONST64(0x0000000808000808), - CONST64(0x0000080008000800), CONST64(0x0000080808000800), CONST64(0x0000080008000808), CONST64(0x0000080808000808), - CONST64(0x0008000008000000), CONST64(0x0008000808000000), CONST64(0x0008000008000008), CONST64(0x0008000808000008), - CONST64(0x0008080008000000), CONST64(0x0008080808000000), CONST64(0x0008080008000008), CONST64(0x0008080808000008), - CONST64(0x0008000008000800), CONST64(0x0008000808000800), CONST64(0x0008000008000808), CONST64(0x0008000808000808), - CONST64(0x0008080008000800), CONST64(0x0008080808000800), CONST64(0x0008080008000808), CONST64(0x0008080808000808), - CONST64(0x0000000008080000), CONST64(0x0000000808080000), CONST64(0x0000000008080008), CONST64(0x0000000808080008), - CONST64(0x0000080008080000), CONST64(0x0000080808080000), CONST64(0x0000080008080008), CONST64(0x0000080808080008), - CONST64(0x0000000008080800), CONST64(0x0000000808080800), CONST64(0x0000000008080808), CONST64(0x0000000808080808), - CONST64(0x0000080008080800), CONST64(0x0000080808080800), CONST64(0x0000080008080808), CONST64(0x0000080808080808), - CONST64(0x0008000008080000), CONST64(0x0008000808080000), CONST64(0x0008000008080008), CONST64(0x0008000808080008), - CONST64(0x0008080008080000), CONST64(0x0008080808080000), CONST64(0x0008080008080008), CONST64(0x0008080808080008), - CONST64(0x0008000008080800), CONST64(0x0008000808080800), CONST64(0x0008000008080808), CONST64(0x0008000808080808), - CONST64(0x0008080008080800), CONST64(0x0008080808080800), CONST64(0x0008080008080808), CONST64(0x0008080808080808), - CONST64(0x0800000008000000), CONST64(0x0800000808000000), CONST64(0x0800000008000008), CONST64(0x0800000808000008), - CONST64(0x0800080008000000), CONST64(0x0800080808000000), CONST64(0x0800080008000008), CONST64(0x0800080808000008), - CONST64(0x0800000008000800), CONST64(0x0800000808000800), CONST64(0x0800000008000808), CONST64(0x0800000808000808), - CONST64(0x0800080008000800), CONST64(0x0800080808000800), CONST64(0x0800080008000808), CONST64(0x0800080808000808), - CONST64(0x0808000008000000), CONST64(0x0808000808000000), CONST64(0x0808000008000008), CONST64(0x0808000808000008), - CONST64(0x0808080008000000), CONST64(0x0808080808000000), CONST64(0x0808080008000008), CONST64(0x0808080808000008), - CONST64(0x0808000008000800), CONST64(0x0808000808000800), CONST64(0x0808000008000808), CONST64(0x0808000808000808), - CONST64(0x0808080008000800), CONST64(0x0808080808000800), CONST64(0x0808080008000808), CONST64(0x0808080808000808), - CONST64(0x0800000008080000), CONST64(0x0800000808080000), CONST64(0x0800000008080008), CONST64(0x0800000808080008), - CONST64(0x0800080008080000), CONST64(0x0800080808080000), CONST64(0x0800080008080008), CONST64(0x0800080808080008), - CONST64(0x0800000008080800), CONST64(0x0800000808080800), CONST64(0x0800000008080808), CONST64(0x0800000808080808), - CONST64(0x0800080008080800), CONST64(0x0800080808080800), CONST64(0x0800080008080808), CONST64(0x0800080808080808), - CONST64(0x0808000008080000), CONST64(0x0808000808080000), CONST64(0x0808000008080008), CONST64(0x0808000808080008), - CONST64(0x0808080008080000), CONST64(0x0808080808080000), CONST64(0x0808080008080008), CONST64(0x0808080808080008), - CONST64(0x0808000008080800), CONST64(0x0808000808080800), CONST64(0x0808000008080808), CONST64(0x0808000808080808), - CONST64(0x0808080008080800), CONST64(0x0808080808080800), CONST64(0x0808080008080808), CONST64(0x0808080808080808) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000000400000000), CONST64(0x0000000000000004), CONST64(0x0000000400000004), - CONST64(0x0000040000000000), CONST64(0x0000040400000000), CONST64(0x0000040000000004), CONST64(0x0000040400000004), - CONST64(0x0000000000000400), CONST64(0x0000000400000400), CONST64(0x0000000000000404), CONST64(0x0000000400000404), - CONST64(0x0000040000000400), CONST64(0x0000040400000400), CONST64(0x0000040000000404), CONST64(0x0000040400000404), - CONST64(0x0004000000000000), CONST64(0x0004000400000000), CONST64(0x0004000000000004), CONST64(0x0004000400000004), - CONST64(0x0004040000000000), CONST64(0x0004040400000000), CONST64(0x0004040000000004), CONST64(0x0004040400000004), - CONST64(0x0004000000000400), CONST64(0x0004000400000400), CONST64(0x0004000000000404), CONST64(0x0004000400000404), - CONST64(0x0004040000000400), CONST64(0x0004040400000400), CONST64(0x0004040000000404), CONST64(0x0004040400000404), - CONST64(0x0000000000040000), CONST64(0x0000000400040000), CONST64(0x0000000000040004), CONST64(0x0000000400040004), - CONST64(0x0000040000040000), CONST64(0x0000040400040000), CONST64(0x0000040000040004), CONST64(0x0000040400040004), - CONST64(0x0000000000040400), CONST64(0x0000000400040400), CONST64(0x0000000000040404), CONST64(0x0000000400040404), - CONST64(0x0000040000040400), CONST64(0x0000040400040400), CONST64(0x0000040000040404), CONST64(0x0000040400040404), - CONST64(0x0004000000040000), CONST64(0x0004000400040000), CONST64(0x0004000000040004), CONST64(0x0004000400040004), - CONST64(0x0004040000040000), CONST64(0x0004040400040000), CONST64(0x0004040000040004), CONST64(0x0004040400040004), - CONST64(0x0004000000040400), CONST64(0x0004000400040400), CONST64(0x0004000000040404), CONST64(0x0004000400040404), - CONST64(0x0004040000040400), CONST64(0x0004040400040400), CONST64(0x0004040000040404), CONST64(0x0004040400040404), - CONST64(0x0400000000000000), CONST64(0x0400000400000000), CONST64(0x0400000000000004), CONST64(0x0400000400000004), - CONST64(0x0400040000000000), CONST64(0x0400040400000000), CONST64(0x0400040000000004), CONST64(0x0400040400000004), - CONST64(0x0400000000000400), CONST64(0x0400000400000400), CONST64(0x0400000000000404), CONST64(0x0400000400000404), - CONST64(0x0400040000000400), CONST64(0x0400040400000400), CONST64(0x0400040000000404), CONST64(0x0400040400000404), - CONST64(0x0404000000000000), CONST64(0x0404000400000000), CONST64(0x0404000000000004), CONST64(0x0404000400000004), - CONST64(0x0404040000000000), CONST64(0x0404040400000000), CONST64(0x0404040000000004), CONST64(0x0404040400000004), - CONST64(0x0404000000000400), CONST64(0x0404000400000400), CONST64(0x0404000000000404), CONST64(0x0404000400000404), - CONST64(0x0404040000000400), CONST64(0x0404040400000400), CONST64(0x0404040000000404), CONST64(0x0404040400000404), - CONST64(0x0400000000040000), CONST64(0x0400000400040000), CONST64(0x0400000000040004), CONST64(0x0400000400040004), - CONST64(0x0400040000040000), CONST64(0x0400040400040000), CONST64(0x0400040000040004), CONST64(0x0400040400040004), - CONST64(0x0400000000040400), CONST64(0x0400000400040400), CONST64(0x0400000000040404), CONST64(0x0400000400040404), - CONST64(0x0400040000040400), CONST64(0x0400040400040400), CONST64(0x0400040000040404), CONST64(0x0400040400040404), - CONST64(0x0404000000040000), CONST64(0x0404000400040000), CONST64(0x0404000000040004), CONST64(0x0404000400040004), - CONST64(0x0404040000040000), CONST64(0x0404040400040000), CONST64(0x0404040000040004), CONST64(0x0404040400040004), - CONST64(0x0404000000040400), CONST64(0x0404000400040400), CONST64(0x0404000000040404), CONST64(0x0404000400040404), - CONST64(0x0404040000040400), CONST64(0x0404040400040400), CONST64(0x0404040000040404), CONST64(0x0404040400040404), - CONST64(0x0000000004000000), CONST64(0x0000000404000000), CONST64(0x0000000004000004), CONST64(0x0000000404000004), - CONST64(0x0000040004000000), CONST64(0x0000040404000000), CONST64(0x0000040004000004), CONST64(0x0000040404000004), - CONST64(0x0000000004000400), CONST64(0x0000000404000400), CONST64(0x0000000004000404), CONST64(0x0000000404000404), - CONST64(0x0000040004000400), CONST64(0x0000040404000400), CONST64(0x0000040004000404), CONST64(0x0000040404000404), - CONST64(0x0004000004000000), CONST64(0x0004000404000000), CONST64(0x0004000004000004), CONST64(0x0004000404000004), - CONST64(0x0004040004000000), CONST64(0x0004040404000000), CONST64(0x0004040004000004), CONST64(0x0004040404000004), - CONST64(0x0004000004000400), CONST64(0x0004000404000400), CONST64(0x0004000004000404), CONST64(0x0004000404000404), - CONST64(0x0004040004000400), CONST64(0x0004040404000400), CONST64(0x0004040004000404), CONST64(0x0004040404000404), - CONST64(0x0000000004040000), CONST64(0x0000000404040000), CONST64(0x0000000004040004), CONST64(0x0000000404040004), - CONST64(0x0000040004040000), CONST64(0x0000040404040000), CONST64(0x0000040004040004), CONST64(0x0000040404040004), - CONST64(0x0000000004040400), CONST64(0x0000000404040400), CONST64(0x0000000004040404), CONST64(0x0000000404040404), - CONST64(0x0000040004040400), CONST64(0x0000040404040400), CONST64(0x0000040004040404), CONST64(0x0000040404040404), - CONST64(0x0004000004040000), CONST64(0x0004000404040000), CONST64(0x0004000004040004), CONST64(0x0004000404040004), - CONST64(0x0004040004040000), CONST64(0x0004040404040000), CONST64(0x0004040004040004), CONST64(0x0004040404040004), - CONST64(0x0004000004040400), CONST64(0x0004000404040400), CONST64(0x0004000004040404), CONST64(0x0004000404040404), - CONST64(0x0004040004040400), CONST64(0x0004040404040400), CONST64(0x0004040004040404), CONST64(0x0004040404040404), - CONST64(0x0400000004000000), CONST64(0x0400000404000000), CONST64(0x0400000004000004), CONST64(0x0400000404000004), - CONST64(0x0400040004000000), CONST64(0x0400040404000000), CONST64(0x0400040004000004), CONST64(0x0400040404000004), - CONST64(0x0400000004000400), CONST64(0x0400000404000400), CONST64(0x0400000004000404), CONST64(0x0400000404000404), - CONST64(0x0400040004000400), CONST64(0x0400040404000400), CONST64(0x0400040004000404), CONST64(0x0400040404000404), - CONST64(0x0404000004000000), CONST64(0x0404000404000000), CONST64(0x0404000004000004), CONST64(0x0404000404000004), - CONST64(0x0404040004000000), CONST64(0x0404040404000000), CONST64(0x0404040004000004), CONST64(0x0404040404000004), - CONST64(0x0404000004000400), CONST64(0x0404000404000400), CONST64(0x0404000004000404), CONST64(0x0404000404000404), - CONST64(0x0404040004000400), CONST64(0x0404040404000400), CONST64(0x0404040004000404), CONST64(0x0404040404000404), - CONST64(0x0400000004040000), CONST64(0x0400000404040000), CONST64(0x0400000004040004), CONST64(0x0400000404040004), - CONST64(0x0400040004040000), CONST64(0x0400040404040000), CONST64(0x0400040004040004), CONST64(0x0400040404040004), - CONST64(0x0400000004040400), CONST64(0x0400000404040400), CONST64(0x0400000004040404), CONST64(0x0400000404040404), - CONST64(0x0400040004040400), CONST64(0x0400040404040400), CONST64(0x0400040004040404), CONST64(0x0400040404040404), - CONST64(0x0404000004040000), CONST64(0x0404000404040000), CONST64(0x0404000004040004), CONST64(0x0404000404040004), - CONST64(0x0404040004040000), CONST64(0x0404040404040000), CONST64(0x0404040004040004), CONST64(0x0404040404040004), - CONST64(0x0404000004040400), CONST64(0x0404000404040400), CONST64(0x0404000004040404), CONST64(0x0404000404040404), - CONST64(0x0404040004040400), CONST64(0x0404040404040400), CONST64(0x0404040004040404), CONST64(0x0404040404040404) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000000200000000), CONST64(0x0000000000000002), CONST64(0x0000000200000002), - CONST64(0x0000020000000000), CONST64(0x0000020200000000), CONST64(0x0000020000000002), CONST64(0x0000020200000002), - CONST64(0x0000000000000200), CONST64(0x0000000200000200), CONST64(0x0000000000000202), CONST64(0x0000000200000202), - CONST64(0x0000020000000200), CONST64(0x0000020200000200), CONST64(0x0000020000000202), CONST64(0x0000020200000202), - CONST64(0x0002000000000000), CONST64(0x0002000200000000), CONST64(0x0002000000000002), CONST64(0x0002000200000002), - CONST64(0x0002020000000000), CONST64(0x0002020200000000), CONST64(0x0002020000000002), CONST64(0x0002020200000002), - CONST64(0x0002000000000200), CONST64(0x0002000200000200), CONST64(0x0002000000000202), CONST64(0x0002000200000202), - CONST64(0x0002020000000200), CONST64(0x0002020200000200), CONST64(0x0002020000000202), CONST64(0x0002020200000202), - CONST64(0x0000000000020000), CONST64(0x0000000200020000), CONST64(0x0000000000020002), CONST64(0x0000000200020002), - CONST64(0x0000020000020000), CONST64(0x0000020200020000), CONST64(0x0000020000020002), CONST64(0x0000020200020002), - CONST64(0x0000000000020200), CONST64(0x0000000200020200), CONST64(0x0000000000020202), CONST64(0x0000000200020202), - CONST64(0x0000020000020200), CONST64(0x0000020200020200), CONST64(0x0000020000020202), CONST64(0x0000020200020202), - CONST64(0x0002000000020000), CONST64(0x0002000200020000), CONST64(0x0002000000020002), CONST64(0x0002000200020002), - CONST64(0x0002020000020000), CONST64(0x0002020200020000), CONST64(0x0002020000020002), CONST64(0x0002020200020002), - CONST64(0x0002000000020200), CONST64(0x0002000200020200), CONST64(0x0002000000020202), CONST64(0x0002000200020202), - CONST64(0x0002020000020200), CONST64(0x0002020200020200), CONST64(0x0002020000020202), CONST64(0x0002020200020202), - CONST64(0x0200000000000000), CONST64(0x0200000200000000), CONST64(0x0200000000000002), CONST64(0x0200000200000002), - CONST64(0x0200020000000000), CONST64(0x0200020200000000), CONST64(0x0200020000000002), CONST64(0x0200020200000002), - CONST64(0x0200000000000200), CONST64(0x0200000200000200), CONST64(0x0200000000000202), CONST64(0x0200000200000202), - CONST64(0x0200020000000200), CONST64(0x0200020200000200), CONST64(0x0200020000000202), CONST64(0x0200020200000202), - CONST64(0x0202000000000000), CONST64(0x0202000200000000), CONST64(0x0202000000000002), CONST64(0x0202000200000002), - CONST64(0x0202020000000000), CONST64(0x0202020200000000), CONST64(0x0202020000000002), CONST64(0x0202020200000002), - CONST64(0x0202000000000200), CONST64(0x0202000200000200), CONST64(0x0202000000000202), CONST64(0x0202000200000202), - CONST64(0x0202020000000200), CONST64(0x0202020200000200), CONST64(0x0202020000000202), CONST64(0x0202020200000202), - CONST64(0x0200000000020000), CONST64(0x0200000200020000), CONST64(0x0200000000020002), CONST64(0x0200000200020002), - CONST64(0x0200020000020000), CONST64(0x0200020200020000), CONST64(0x0200020000020002), CONST64(0x0200020200020002), - CONST64(0x0200000000020200), CONST64(0x0200000200020200), CONST64(0x0200000000020202), CONST64(0x0200000200020202), - CONST64(0x0200020000020200), CONST64(0x0200020200020200), CONST64(0x0200020000020202), CONST64(0x0200020200020202), - CONST64(0x0202000000020000), CONST64(0x0202000200020000), CONST64(0x0202000000020002), CONST64(0x0202000200020002), - CONST64(0x0202020000020000), CONST64(0x0202020200020000), CONST64(0x0202020000020002), CONST64(0x0202020200020002), - CONST64(0x0202000000020200), CONST64(0x0202000200020200), CONST64(0x0202000000020202), CONST64(0x0202000200020202), - CONST64(0x0202020000020200), CONST64(0x0202020200020200), CONST64(0x0202020000020202), CONST64(0x0202020200020202), - CONST64(0x0000000002000000), CONST64(0x0000000202000000), CONST64(0x0000000002000002), CONST64(0x0000000202000002), - CONST64(0x0000020002000000), CONST64(0x0000020202000000), CONST64(0x0000020002000002), CONST64(0x0000020202000002), - CONST64(0x0000000002000200), CONST64(0x0000000202000200), CONST64(0x0000000002000202), CONST64(0x0000000202000202), - CONST64(0x0000020002000200), CONST64(0x0000020202000200), CONST64(0x0000020002000202), CONST64(0x0000020202000202), - CONST64(0x0002000002000000), CONST64(0x0002000202000000), CONST64(0x0002000002000002), CONST64(0x0002000202000002), - CONST64(0x0002020002000000), CONST64(0x0002020202000000), CONST64(0x0002020002000002), CONST64(0x0002020202000002), - CONST64(0x0002000002000200), CONST64(0x0002000202000200), CONST64(0x0002000002000202), CONST64(0x0002000202000202), - CONST64(0x0002020002000200), CONST64(0x0002020202000200), CONST64(0x0002020002000202), CONST64(0x0002020202000202), - CONST64(0x0000000002020000), CONST64(0x0000000202020000), CONST64(0x0000000002020002), CONST64(0x0000000202020002), - CONST64(0x0000020002020000), CONST64(0x0000020202020000), CONST64(0x0000020002020002), CONST64(0x0000020202020002), - CONST64(0x0000000002020200), CONST64(0x0000000202020200), CONST64(0x0000000002020202), CONST64(0x0000000202020202), - CONST64(0x0000020002020200), CONST64(0x0000020202020200), CONST64(0x0000020002020202), CONST64(0x0000020202020202), - CONST64(0x0002000002020000), CONST64(0x0002000202020000), CONST64(0x0002000002020002), CONST64(0x0002000202020002), - CONST64(0x0002020002020000), CONST64(0x0002020202020000), CONST64(0x0002020002020002), CONST64(0x0002020202020002), - CONST64(0x0002000002020200), CONST64(0x0002000202020200), CONST64(0x0002000002020202), CONST64(0x0002000202020202), - CONST64(0x0002020002020200), CONST64(0x0002020202020200), CONST64(0x0002020002020202), CONST64(0x0002020202020202), - CONST64(0x0200000002000000), CONST64(0x0200000202000000), CONST64(0x0200000002000002), CONST64(0x0200000202000002), - CONST64(0x0200020002000000), CONST64(0x0200020202000000), CONST64(0x0200020002000002), CONST64(0x0200020202000002), - CONST64(0x0200000002000200), CONST64(0x0200000202000200), CONST64(0x0200000002000202), CONST64(0x0200000202000202), - CONST64(0x0200020002000200), CONST64(0x0200020202000200), CONST64(0x0200020002000202), CONST64(0x0200020202000202), - CONST64(0x0202000002000000), CONST64(0x0202000202000000), CONST64(0x0202000002000002), CONST64(0x0202000202000002), - CONST64(0x0202020002000000), CONST64(0x0202020202000000), CONST64(0x0202020002000002), CONST64(0x0202020202000002), - CONST64(0x0202000002000200), CONST64(0x0202000202000200), CONST64(0x0202000002000202), CONST64(0x0202000202000202), - CONST64(0x0202020002000200), CONST64(0x0202020202000200), CONST64(0x0202020002000202), CONST64(0x0202020202000202), - CONST64(0x0200000002020000), CONST64(0x0200000202020000), CONST64(0x0200000002020002), CONST64(0x0200000202020002), - CONST64(0x0200020002020000), CONST64(0x0200020202020000), CONST64(0x0200020002020002), CONST64(0x0200020202020002), - CONST64(0x0200000002020200), CONST64(0x0200000202020200), CONST64(0x0200000002020202), CONST64(0x0200000202020202), - CONST64(0x0200020002020200), CONST64(0x0200020202020200), CONST64(0x0200020002020202), CONST64(0x0200020202020202), - CONST64(0x0202000002020000), CONST64(0x0202000202020000), CONST64(0x0202000002020002), CONST64(0x0202000202020002), - CONST64(0x0202020002020000), CONST64(0x0202020202020000), CONST64(0x0202020002020002), CONST64(0x0202020202020002), - CONST64(0x0202000002020200), CONST64(0x0202000202020200), CONST64(0x0202000002020202), CONST64(0x0202000202020202), - CONST64(0x0202020002020200), CONST64(0x0202020202020200), CONST64(0x0202020002020202), CONST64(0x0202020202020202) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000010000000000), CONST64(0x0000000000000100), CONST64(0x0000010000000100), - CONST64(0x0001000000000000), CONST64(0x0001010000000000), CONST64(0x0001000000000100), CONST64(0x0001010000000100), - CONST64(0x0000000000010000), CONST64(0x0000010000010000), CONST64(0x0000000000010100), CONST64(0x0000010000010100), - CONST64(0x0001000000010000), CONST64(0x0001010000010000), CONST64(0x0001000000010100), CONST64(0x0001010000010100), - CONST64(0x0100000000000000), CONST64(0x0100010000000000), CONST64(0x0100000000000100), CONST64(0x0100010000000100), - CONST64(0x0101000000000000), CONST64(0x0101010000000000), CONST64(0x0101000000000100), CONST64(0x0101010000000100), - CONST64(0x0100000000010000), CONST64(0x0100010000010000), CONST64(0x0100000000010100), CONST64(0x0100010000010100), - CONST64(0x0101000000010000), CONST64(0x0101010000010000), CONST64(0x0101000000010100), CONST64(0x0101010000010100), - CONST64(0x0000000001000000), CONST64(0x0000010001000000), CONST64(0x0000000001000100), CONST64(0x0000010001000100), - CONST64(0x0001000001000000), CONST64(0x0001010001000000), CONST64(0x0001000001000100), CONST64(0x0001010001000100), - CONST64(0x0000000001010000), CONST64(0x0000010001010000), CONST64(0x0000000001010100), CONST64(0x0000010001010100), - CONST64(0x0001000001010000), CONST64(0x0001010001010000), CONST64(0x0001000001010100), CONST64(0x0001010001010100), - CONST64(0x0100000001000000), CONST64(0x0100010001000000), CONST64(0x0100000001000100), CONST64(0x0100010001000100), - CONST64(0x0101000001000000), CONST64(0x0101010001000000), CONST64(0x0101000001000100), CONST64(0x0101010001000100), - CONST64(0x0100000001010000), CONST64(0x0100010001010000), CONST64(0x0100000001010100), CONST64(0x0100010001010100), - CONST64(0x0101000001010000), CONST64(0x0101010001010000), CONST64(0x0101000001010100), CONST64(0x0101010001010100), - CONST64(0x0000000100000000), CONST64(0x0000010100000000), CONST64(0x0000000100000100), CONST64(0x0000010100000100), - CONST64(0x0001000100000000), CONST64(0x0001010100000000), CONST64(0x0001000100000100), CONST64(0x0001010100000100), - CONST64(0x0000000100010000), CONST64(0x0000010100010000), CONST64(0x0000000100010100), CONST64(0x0000010100010100), - CONST64(0x0001000100010000), CONST64(0x0001010100010000), CONST64(0x0001000100010100), CONST64(0x0001010100010100), - CONST64(0x0100000100000000), CONST64(0x0100010100000000), CONST64(0x0100000100000100), CONST64(0x0100010100000100), - CONST64(0x0101000100000000), CONST64(0x0101010100000000), CONST64(0x0101000100000100), CONST64(0x0101010100000100), - CONST64(0x0100000100010000), CONST64(0x0100010100010000), CONST64(0x0100000100010100), CONST64(0x0100010100010100), - CONST64(0x0101000100010000), CONST64(0x0101010100010000), CONST64(0x0101000100010100), CONST64(0x0101010100010100), - CONST64(0x0000000101000000), CONST64(0x0000010101000000), CONST64(0x0000000101000100), CONST64(0x0000010101000100), - CONST64(0x0001000101000000), CONST64(0x0001010101000000), CONST64(0x0001000101000100), CONST64(0x0001010101000100), - CONST64(0x0000000101010000), CONST64(0x0000010101010000), CONST64(0x0000000101010100), CONST64(0x0000010101010100), - CONST64(0x0001000101010000), CONST64(0x0001010101010000), CONST64(0x0001000101010100), CONST64(0x0001010101010100), - CONST64(0x0100000101000000), CONST64(0x0100010101000000), CONST64(0x0100000101000100), CONST64(0x0100010101000100), - CONST64(0x0101000101000000), CONST64(0x0101010101000000), CONST64(0x0101000101000100), CONST64(0x0101010101000100), - CONST64(0x0100000101010000), CONST64(0x0100010101010000), CONST64(0x0100000101010100), CONST64(0x0100010101010100), - CONST64(0x0101000101010000), CONST64(0x0101010101010000), CONST64(0x0101000101010100), CONST64(0x0101010101010100), - CONST64(0x0000000000000001), CONST64(0x0000010000000001), CONST64(0x0000000000000101), CONST64(0x0000010000000101), - CONST64(0x0001000000000001), CONST64(0x0001010000000001), CONST64(0x0001000000000101), CONST64(0x0001010000000101), - CONST64(0x0000000000010001), CONST64(0x0000010000010001), CONST64(0x0000000000010101), CONST64(0x0000010000010101), - CONST64(0x0001000000010001), CONST64(0x0001010000010001), CONST64(0x0001000000010101), CONST64(0x0001010000010101), - CONST64(0x0100000000000001), CONST64(0x0100010000000001), CONST64(0x0100000000000101), CONST64(0x0100010000000101), - CONST64(0x0101000000000001), CONST64(0x0101010000000001), CONST64(0x0101000000000101), CONST64(0x0101010000000101), - CONST64(0x0100000000010001), CONST64(0x0100010000010001), CONST64(0x0100000000010101), CONST64(0x0100010000010101), - CONST64(0x0101000000010001), CONST64(0x0101010000010001), CONST64(0x0101000000010101), CONST64(0x0101010000010101), - CONST64(0x0000000001000001), CONST64(0x0000010001000001), CONST64(0x0000000001000101), CONST64(0x0000010001000101), - CONST64(0x0001000001000001), CONST64(0x0001010001000001), CONST64(0x0001000001000101), CONST64(0x0001010001000101), - CONST64(0x0000000001010001), CONST64(0x0000010001010001), CONST64(0x0000000001010101), CONST64(0x0000010001010101), - CONST64(0x0001000001010001), CONST64(0x0001010001010001), CONST64(0x0001000001010101), CONST64(0x0001010001010101), - CONST64(0x0100000001000001), CONST64(0x0100010001000001), CONST64(0x0100000001000101), CONST64(0x0100010001000101), - CONST64(0x0101000001000001), CONST64(0x0101010001000001), CONST64(0x0101000001000101), CONST64(0x0101010001000101), - CONST64(0x0100000001010001), CONST64(0x0100010001010001), CONST64(0x0100000001010101), CONST64(0x0100010001010101), - CONST64(0x0101000001010001), CONST64(0x0101010001010001), CONST64(0x0101000001010101), CONST64(0x0101010001010101), - CONST64(0x0000000100000001), CONST64(0x0000010100000001), CONST64(0x0000000100000101), CONST64(0x0000010100000101), - CONST64(0x0001000100000001), CONST64(0x0001010100000001), CONST64(0x0001000100000101), CONST64(0x0001010100000101), - CONST64(0x0000000100010001), CONST64(0x0000010100010001), CONST64(0x0000000100010101), CONST64(0x0000010100010101), - CONST64(0x0001000100010001), CONST64(0x0001010100010001), CONST64(0x0001000100010101), CONST64(0x0001010100010101), - CONST64(0x0100000100000001), CONST64(0x0100010100000001), CONST64(0x0100000100000101), CONST64(0x0100010100000101), - CONST64(0x0101000100000001), CONST64(0x0101010100000001), CONST64(0x0101000100000101), CONST64(0x0101010100000101), - CONST64(0x0100000100010001), CONST64(0x0100010100010001), CONST64(0x0100000100010101), CONST64(0x0100010100010101), - CONST64(0x0101000100010001), CONST64(0x0101010100010001), CONST64(0x0101000100010101), CONST64(0x0101010100010101), - CONST64(0x0000000101000001), CONST64(0x0000010101000001), CONST64(0x0000000101000101), CONST64(0x0000010101000101), - CONST64(0x0001000101000001), CONST64(0x0001010101000001), CONST64(0x0001000101000101), CONST64(0x0001010101000101), - CONST64(0x0000000101010001), CONST64(0x0000010101010001), CONST64(0x0000000101010101), CONST64(0x0000010101010101), - CONST64(0x0001000101010001), CONST64(0x0001010101010001), CONST64(0x0001000101010101), CONST64(0x0001010101010101), - CONST64(0x0100000101000001), CONST64(0x0100010101000001), CONST64(0x0100000101000101), CONST64(0x0100010101000101), - CONST64(0x0101000101000001), CONST64(0x0101010101000001), CONST64(0x0101000101000101), CONST64(0x0101010101000101), - CONST64(0x0100000101010001), CONST64(0x0100010101010001), CONST64(0x0100000101010101), CONST64(0x0100010101010101), - CONST64(0x0101000101010001), CONST64(0x0101010101010001), CONST64(0x0101000101010101), CONST64(0x0101010101010101) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000008000000000), CONST64(0x0000000000000080), CONST64(0x0000008000000080), - CONST64(0x0000800000000000), CONST64(0x0000808000000000), CONST64(0x0000800000000080), CONST64(0x0000808000000080), - CONST64(0x0000000000008000), CONST64(0x0000008000008000), CONST64(0x0000000000008080), CONST64(0x0000008000008080), - CONST64(0x0000800000008000), CONST64(0x0000808000008000), CONST64(0x0000800000008080), CONST64(0x0000808000008080), - CONST64(0x0080000000000000), CONST64(0x0080008000000000), CONST64(0x0080000000000080), CONST64(0x0080008000000080), - CONST64(0x0080800000000000), CONST64(0x0080808000000000), CONST64(0x0080800000000080), CONST64(0x0080808000000080), - CONST64(0x0080000000008000), CONST64(0x0080008000008000), CONST64(0x0080000000008080), CONST64(0x0080008000008080), - CONST64(0x0080800000008000), CONST64(0x0080808000008000), CONST64(0x0080800000008080), CONST64(0x0080808000008080), - CONST64(0x0000000000800000), CONST64(0x0000008000800000), CONST64(0x0000000000800080), CONST64(0x0000008000800080), - CONST64(0x0000800000800000), CONST64(0x0000808000800000), CONST64(0x0000800000800080), CONST64(0x0000808000800080), - CONST64(0x0000000000808000), CONST64(0x0000008000808000), CONST64(0x0000000000808080), CONST64(0x0000008000808080), - CONST64(0x0000800000808000), CONST64(0x0000808000808000), CONST64(0x0000800000808080), CONST64(0x0000808000808080), - CONST64(0x0080000000800000), CONST64(0x0080008000800000), CONST64(0x0080000000800080), CONST64(0x0080008000800080), - CONST64(0x0080800000800000), CONST64(0x0080808000800000), CONST64(0x0080800000800080), CONST64(0x0080808000800080), - CONST64(0x0080000000808000), CONST64(0x0080008000808000), CONST64(0x0080000000808080), CONST64(0x0080008000808080), - CONST64(0x0080800000808000), CONST64(0x0080808000808000), CONST64(0x0080800000808080), CONST64(0x0080808000808080), - CONST64(0x8000000000000000), CONST64(0x8000008000000000), CONST64(0x8000000000000080), CONST64(0x8000008000000080), - CONST64(0x8000800000000000), CONST64(0x8000808000000000), CONST64(0x8000800000000080), CONST64(0x8000808000000080), - CONST64(0x8000000000008000), CONST64(0x8000008000008000), CONST64(0x8000000000008080), CONST64(0x8000008000008080), - CONST64(0x8000800000008000), CONST64(0x8000808000008000), CONST64(0x8000800000008080), CONST64(0x8000808000008080), - CONST64(0x8080000000000000), CONST64(0x8080008000000000), CONST64(0x8080000000000080), CONST64(0x8080008000000080), - CONST64(0x8080800000000000), CONST64(0x8080808000000000), CONST64(0x8080800000000080), CONST64(0x8080808000000080), - CONST64(0x8080000000008000), CONST64(0x8080008000008000), CONST64(0x8080000000008080), CONST64(0x8080008000008080), - CONST64(0x8080800000008000), CONST64(0x8080808000008000), CONST64(0x8080800000008080), CONST64(0x8080808000008080), - CONST64(0x8000000000800000), CONST64(0x8000008000800000), CONST64(0x8000000000800080), CONST64(0x8000008000800080), - CONST64(0x8000800000800000), CONST64(0x8000808000800000), CONST64(0x8000800000800080), CONST64(0x8000808000800080), - CONST64(0x8000000000808000), CONST64(0x8000008000808000), CONST64(0x8000000000808080), CONST64(0x8000008000808080), - CONST64(0x8000800000808000), CONST64(0x8000808000808000), CONST64(0x8000800000808080), CONST64(0x8000808000808080), - CONST64(0x8080000000800000), CONST64(0x8080008000800000), CONST64(0x8080000000800080), CONST64(0x8080008000800080), - CONST64(0x8080800000800000), CONST64(0x8080808000800000), CONST64(0x8080800000800080), CONST64(0x8080808000800080), - CONST64(0x8080000000808000), CONST64(0x8080008000808000), CONST64(0x8080000000808080), CONST64(0x8080008000808080), - CONST64(0x8080800000808000), CONST64(0x8080808000808000), CONST64(0x8080800000808080), CONST64(0x8080808000808080), - CONST64(0x0000000080000000), CONST64(0x0000008080000000), CONST64(0x0000000080000080), CONST64(0x0000008080000080), - CONST64(0x0000800080000000), CONST64(0x0000808080000000), CONST64(0x0000800080000080), CONST64(0x0000808080000080), - CONST64(0x0000000080008000), CONST64(0x0000008080008000), CONST64(0x0000000080008080), CONST64(0x0000008080008080), - CONST64(0x0000800080008000), CONST64(0x0000808080008000), CONST64(0x0000800080008080), CONST64(0x0000808080008080), - CONST64(0x0080000080000000), CONST64(0x0080008080000000), CONST64(0x0080000080000080), CONST64(0x0080008080000080), - CONST64(0x0080800080000000), CONST64(0x0080808080000000), CONST64(0x0080800080000080), CONST64(0x0080808080000080), - CONST64(0x0080000080008000), CONST64(0x0080008080008000), CONST64(0x0080000080008080), CONST64(0x0080008080008080), - CONST64(0x0080800080008000), CONST64(0x0080808080008000), CONST64(0x0080800080008080), CONST64(0x0080808080008080), - CONST64(0x0000000080800000), CONST64(0x0000008080800000), CONST64(0x0000000080800080), CONST64(0x0000008080800080), - CONST64(0x0000800080800000), CONST64(0x0000808080800000), CONST64(0x0000800080800080), CONST64(0x0000808080800080), - CONST64(0x0000000080808000), CONST64(0x0000008080808000), CONST64(0x0000000080808080), CONST64(0x0000008080808080), - CONST64(0x0000800080808000), CONST64(0x0000808080808000), CONST64(0x0000800080808080), CONST64(0x0000808080808080), - CONST64(0x0080000080800000), CONST64(0x0080008080800000), CONST64(0x0080000080800080), CONST64(0x0080008080800080), - CONST64(0x0080800080800000), CONST64(0x0080808080800000), CONST64(0x0080800080800080), CONST64(0x0080808080800080), - CONST64(0x0080000080808000), CONST64(0x0080008080808000), CONST64(0x0080000080808080), CONST64(0x0080008080808080), - CONST64(0x0080800080808000), CONST64(0x0080808080808000), CONST64(0x0080800080808080), CONST64(0x0080808080808080), - CONST64(0x8000000080000000), CONST64(0x8000008080000000), CONST64(0x8000000080000080), CONST64(0x8000008080000080), - CONST64(0x8000800080000000), CONST64(0x8000808080000000), CONST64(0x8000800080000080), CONST64(0x8000808080000080), - CONST64(0x8000000080008000), CONST64(0x8000008080008000), CONST64(0x8000000080008080), CONST64(0x8000008080008080), - CONST64(0x8000800080008000), CONST64(0x8000808080008000), CONST64(0x8000800080008080), CONST64(0x8000808080008080), - CONST64(0x8080000080000000), CONST64(0x8080008080000000), CONST64(0x8080000080000080), CONST64(0x8080008080000080), - CONST64(0x8080800080000000), CONST64(0x8080808080000000), CONST64(0x8080800080000080), CONST64(0x8080808080000080), - CONST64(0x8080000080008000), CONST64(0x8080008080008000), CONST64(0x8080000080008080), CONST64(0x8080008080008080), - CONST64(0x8080800080008000), CONST64(0x8080808080008000), CONST64(0x8080800080008080), CONST64(0x8080808080008080), - CONST64(0x8000000080800000), CONST64(0x8000008080800000), CONST64(0x8000000080800080), CONST64(0x8000008080800080), - CONST64(0x8000800080800000), CONST64(0x8000808080800000), CONST64(0x8000800080800080), CONST64(0x8000808080800080), - CONST64(0x8000000080808000), CONST64(0x8000008080808000), CONST64(0x8000000080808080), CONST64(0x8000008080808080), - CONST64(0x8000800080808000), CONST64(0x8000808080808000), CONST64(0x8000800080808080), CONST64(0x8000808080808080), - CONST64(0x8080000080800000), CONST64(0x8080008080800000), CONST64(0x8080000080800080), CONST64(0x8080008080800080), - CONST64(0x8080800080800000), CONST64(0x8080808080800000), CONST64(0x8080800080800080), CONST64(0x8080808080800080), - CONST64(0x8080000080808000), CONST64(0x8080008080808000), CONST64(0x8080000080808080), CONST64(0x8080008080808080), - CONST64(0x8080800080808000), CONST64(0x8080808080808000), CONST64(0x8080800080808080), CONST64(0x8080808080808080) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000004000000000), CONST64(0x0000000000000040), CONST64(0x0000004000000040), - CONST64(0x0000400000000000), CONST64(0x0000404000000000), CONST64(0x0000400000000040), CONST64(0x0000404000000040), - CONST64(0x0000000000004000), CONST64(0x0000004000004000), CONST64(0x0000000000004040), CONST64(0x0000004000004040), - CONST64(0x0000400000004000), CONST64(0x0000404000004000), CONST64(0x0000400000004040), CONST64(0x0000404000004040), - CONST64(0x0040000000000000), CONST64(0x0040004000000000), CONST64(0x0040000000000040), CONST64(0x0040004000000040), - CONST64(0x0040400000000000), CONST64(0x0040404000000000), CONST64(0x0040400000000040), CONST64(0x0040404000000040), - CONST64(0x0040000000004000), CONST64(0x0040004000004000), CONST64(0x0040000000004040), CONST64(0x0040004000004040), - CONST64(0x0040400000004000), CONST64(0x0040404000004000), CONST64(0x0040400000004040), CONST64(0x0040404000004040), - CONST64(0x0000000000400000), CONST64(0x0000004000400000), CONST64(0x0000000000400040), CONST64(0x0000004000400040), - CONST64(0x0000400000400000), CONST64(0x0000404000400000), CONST64(0x0000400000400040), CONST64(0x0000404000400040), - CONST64(0x0000000000404000), CONST64(0x0000004000404000), CONST64(0x0000000000404040), CONST64(0x0000004000404040), - CONST64(0x0000400000404000), CONST64(0x0000404000404000), CONST64(0x0000400000404040), CONST64(0x0000404000404040), - CONST64(0x0040000000400000), CONST64(0x0040004000400000), CONST64(0x0040000000400040), CONST64(0x0040004000400040), - CONST64(0x0040400000400000), CONST64(0x0040404000400000), CONST64(0x0040400000400040), CONST64(0x0040404000400040), - CONST64(0x0040000000404000), CONST64(0x0040004000404000), CONST64(0x0040000000404040), CONST64(0x0040004000404040), - CONST64(0x0040400000404000), CONST64(0x0040404000404000), CONST64(0x0040400000404040), CONST64(0x0040404000404040), - CONST64(0x4000000000000000), CONST64(0x4000004000000000), CONST64(0x4000000000000040), CONST64(0x4000004000000040), - CONST64(0x4000400000000000), CONST64(0x4000404000000000), CONST64(0x4000400000000040), CONST64(0x4000404000000040), - CONST64(0x4000000000004000), CONST64(0x4000004000004000), CONST64(0x4000000000004040), CONST64(0x4000004000004040), - CONST64(0x4000400000004000), CONST64(0x4000404000004000), CONST64(0x4000400000004040), CONST64(0x4000404000004040), - CONST64(0x4040000000000000), CONST64(0x4040004000000000), CONST64(0x4040000000000040), CONST64(0x4040004000000040), - CONST64(0x4040400000000000), CONST64(0x4040404000000000), CONST64(0x4040400000000040), CONST64(0x4040404000000040), - CONST64(0x4040000000004000), CONST64(0x4040004000004000), CONST64(0x4040000000004040), CONST64(0x4040004000004040), - CONST64(0x4040400000004000), CONST64(0x4040404000004000), CONST64(0x4040400000004040), CONST64(0x4040404000004040), - CONST64(0x4000000000400000), CONST64(0x4000004000400000), CONST64(0x4000000000400040), CONST64(0x4000004000400040), - CONST64(0x4000400000400000), CONST64(0x4000404000400000), CONST64(0x4000400000400040), CONST64(0x4000404000400040), - CONST64(0x4000000000404000), CONST64(0x4000004000404000), CONST64(0x4000000000404040), CONST64(0x4000004000404040), - CONST64(0x4000400000404000), CONST64(0x4000404000404000), CONST64(0x4000400000404040), CONST64(0x4000404000404040), - CONST64(0x4040000000400000), CONST64(0x4040004000400000), CONST64(0x4040000000400040), CONST64(0x4040004000400040), - CONST64(0x4040400000400000), CONST64(0x4040404000400000), CONST64(0x4040400000400040), CONST64(0x4040404000400040), - CONST64(0x4040000000404000), CONST64(0x4040004000404000), CONST64(0x4040000000404040), CONST64(0x4040004000404040), - CONST64(0x4040400000404000), CONST64(0x4040404000404000), CONST64(0x4040400000404040), CONST64(0x4040404000404040), - CONST64(0x0000000040000000), CONST64(0x0000004040000000), CONST64(0x0000000040000040), CONST64(0x0000004040000040), - CONST64(0x0000400040000000), CONST64(0x0000404040000000), CONST64(0x0000400040000040), CONST64(0x0000404040000040), - CONST64(0x0000000040004000), CONST64(0x0000004040004000), CONST64(0x0000000040004040), CONST64(0x0000004040004040), - CONST64(0x0000400040004000), CONST64(0x0000404040004000), CONST64(0x0000400040004040), CONST64(0x0000404040004040), - CONST64(0x0040000040000000), CONST64(0x0040004040000000), CONST64(0x0040000040000040), CONST64(0x0040004040000040), - CONST64(0x0040400040000000), CONST64(0x0040404040000000), CONST64(0x0040400040000040), CONST64(0x0040404040000040), - CONST64(0x0040000040004000), CONST64(0x0040004040004000), CONST64(0x0040000040004040), CONST64(0x0040004040004040), - CONST64(0x0040400040004000), CONST64(0x0040404040004000), CONST64(0x0040400040004040), CONST64(0x0040404040004040), - CONST64(0x0000000040400000), CONST64(0x0000004040400000), CONST64(0x0000000040400040), CONST64(0x0000004040400040), - CONST64(0x0000400040400000), CONST64(0x0000404040400000), CONST64(0x0000400040400040), CONST64(0x0000404040400040), - CONST64(0x0000000040404000), CONST64(0x0000004040404000), CONST64(0x0000000040404040), CONST64(0x0000004040404040), - CONST64(0x0000400040404000), CONST64(0x0000404040404000), CONST64(0x0000400040404040), CONST64(0x0000404040404040), - CONST64(0x0040000040400000), CONST64(0x0040004040400000), CONST64(0x0040000040400040), CONST64(0x0040004040400040), - CONST64(0x0040400040400000), CONST64(0x0040404040400000), CONST64(0x0040400040400040), CONST64(0x0040404040400040), - CONST64(0x0040000040404000), CONST64(0x0040004040404000), CONST64(0x0040000040404040), CONST64(0x0040004040404040), - CONST64(0x0040400040404000), CONST64(0x0040404040404000), CONST64(0x0040400040404040), CONST64(0x0040404040404040), - CONST64(0x4000000040000000), CONST64(0x4000004040000000), CONST64(0x4000000040000040), CONST64(0x4000004040000040), - CONST64(0x4000400040000000), CONST64(0x4000404040000000), CONST64(0x4000400040000040), CONST64(0x4000404040000040), - CONST64(0x4000000040004000), CONST64(0x4000004040004000), CONST64(0x4000000040004040), CONST64(0x4000004040004040), - CONST64(0x4000400040004000), CONST64(0x4000404040004000), CONST64(0x4000400040004040), CONST64(0x4000404040004040), - CONST64(0x4040000040000000), CONST64(0x4040004040000000), CONST64(0x4040000040000040), CONST64(0x4040004040000040), - CONST64(0x4040400040000000), CONST64(0x4040404040000000), CONST64(0x4040400040000040), CONST64(0x4040404040000040), - CONST64(0x4040000040004000), CONST64(0x4040004040004000), CONST64(0x4040000040004040), CONST64(0x4040004040004040), - CONST64(0x4040400040004000), CONST64(0x4040404040004000), CONST64(0x4040400040004040), CONST64(0x4040404040004040), - CONST64(0x4000000040400000), CONST64(0x4000004040400000), CONST64(0x4000000040400040), CONST64(0x4000004040400040), - CONST64(0x4000400040400000), CONST64(0x4000404040400000), CONST64(0x4000400040400040), CONST64(0x4000404040400040), - CONST64(0x4000000040404000), CONST64(0x4000004040404000), CONST64(0x4000000040404040), CONST64(0x4000004040404040), - CONST64(0x4000400040404000), CONST64(0x4000404040404000), CONST64(0x4000400040404040), CONST64(0x4000404040404040), - CONST64(0x4040000040400000), CONST64(0x4040004040400000), CONST64(0x4040000040400040), CONST64(0x4040004040400040), - CONST64(0x4040400040400000), CONST64(0x4040404040400000), CONST64(0x4040400040400040), CONST64(0x4040404040400040), - CONST64(0x4040000040404000), CONST64(0x4040004040404000), CONST64(0x4040000040404040), CONST64(0x4040004040404040), - CONST64(0x4040400040404000), CONST64(0x4040404040404000), CONST64(0x4040400040404040), CONST64(0x4040404040404040) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000002000000000), CONST64(0x0000000000000020), CONST64(0x0000002000000020), - CONST64(0x0000200000000000), CONST64(0x0000202000000000), CONST64(0x0000200000000020), CONST64(0x0000202000000020), - CONST64(0x0000000000002000), CONST64(0x0000002000002000), CONST64(0x0000000000002020), CONST64(0x0000002000002020), - CONST64(0x0000200000002000), CONST64(0x0000202000002000), CONST64(0x0000200000002020), CONST64(0x0000202000002020), - CONST64(0x0020000000000000), CONST64(0x0020002000000000), CONST64(0x0020000000000020), CONST64(0x0020002000000020), - CONST64(0x0020200000000000), CONST64(0x0020202000000000), CONST64(0x0020200000000020), CONST64(0x0020202000000020), - CONST64(0x0020000000002000), CONST64(0x0020002000002000), CONST64(0x0020000000002020), CONST64(0x0020002000002020), - CONST64(0x0020200000002000), CONST64(0x0020202000002000), CONST64(0x0020200000002020), CONST64(0x0020202000002020), - CONST64(0x0000000000200000), CONST64(0x0000002000200000), CONST64(0x0000000000200020), CONST64(0x0000002000200020), - CONST64(0x0000200000200000), CONST64(0x0000202000200000), CONST64(0x0000200000200020), CONST64(0x0000202000200020), - CONST64(0x0000000000202000), CONST64(0x0000002000202000), CONST64(0x0000000000202020), CONST64(0x0000002000202020), - CONST64(0x0000200000202000), CONST64(0x0000202000202000), CONST64(0x0000200000202020), CONST64(0x0000202000202020), - CONST64(0x0020000000200000), CONST64(0x0020002000200000), CONST64(0x0020000000200020), CONST64(0x0020002000200020), - CONST64(0x0020200000200000), CONST64(0x0020202000200000), CONST64(0x0020200000200020), CONST64(0x0020202000200020), - CONST64(0x0020000000202000), CONST64(0x0020002000202000), CONST64(0x0020000000202020), CONST64(0x0020002000202020), - CONST64(0x0020200000202000), CONST64(0x0020202000202000), CONST64(0x0020200000202020), CONST64(0x0020202000202020), - CONST64(0x2000000000000000), CONST64(0x2000002000000000), CONST64(0x2000000000000020), CONST64(0x2000002000000020), - CONST64(0x2000200000000000), CONST64(0x2000202000000000), CONST64(0x2000200000000020), CONST64(0x2000202000000020), - CONST64(0x2000000000002000), CONST64(0x2000002000002000), CONST64(0x2000000000002020), CONST64(0x2000002000002020), - CONST64(0x2000200000002000), CONST64(0x2000202000002000), CONST64(0x2000200000002020), CONST64(0x2000202000002020), - CONST64(0x2020000000000000), CONST64(0x2020002000000000), CONST64(0x2020000000000020), CONST64(0x2020002000000020), - CONST64(0x2020200000000000), CONST64(0x2020202000000000), CONST64(0x2020200000000020), CONST64(0x2020202000000020), - CONST64(0x2020000000002000), CONST64(0x2020002000002000), CONST64(0x2020000000002020), CONST64(0x2020002000002020), - CONST64(0x2020200000002000), CONST64(0x2020202000002000), CONST64(0x2020200000002020), CONST64(0x2020202000002020), - CONST64(0x2000000000200000), CONST64(0x2000002000200000), CONST64(0x2000000000200020), CONST64(0x2000002000200020), - CONST64(0x2000200000200000), CONST64(0x2000202000200000), CONST64(0x2000200000200020), CONST64(0x2000202000200020), - CONST64(0x2000000000202000), CONST64(0x2000002000202000), CONST64(0x2000000000202020), CONST64(0x2000002000202020), - CONST64(0x2000200000202000), CONST64(0x2000202000202000), CONST64(0x2000200000202020), CONST64(0x2000202000202020), - CONST64(0x2020000000200000), CONST64(0x2020002000200000), CONST64(0x2020000000200020), CONST64(0x2020002000200020), - CONST64(0x2020200000200000), CONST64(0x2020202000200000), CONST64(0x2020200000200020), CONST64(0x2020202000200020), - CONST64(0x2020000000202000), CONST64(0x2020002000202000), CONST64(0x2020000000202020), CONST64(0x2020002000202020), - CONST64(0x2020200000202000), CONST64(0x2020202000202000), CONST64(0x2020200000202020), CONST64(0x2020202000202020), - CONST64(0x0000000020000000), CONST64(0x0000002020000000), CONST64(0x0000000020000020), CONST64(0x0000002020000020), - CONST64(0x0000200020000000), CONST64(0x0000202020000000), CONST64(0x0000200020000020), CONST64(0x0000202020000020), - CONST64(0x0000000020002000), CONST64(0x0000002020002000), CONST64(0x0000000020002020), CONST64(0x0000002020002020), - CONST64(0x0000200020002000), CONST64(0x0000202020002000), CONST64(0x0000200020002020), CONST64(0x0000202020002020), - CONST64(0x0020000020000000), CONST64(0x0020002020000000), CONST64(0x0020000020000020), CONST64(0x0020002020000020), - CONST64(0x0020200020000000), CONST64(0x0020202020000000), CONST64(0x0020200020000020), CONST64(0x0020202020000020), - CONST64(0x0020000020002000), CONST64(0x0020002020002000), CONST64(0x0020000020002020), CONST64(0x0020002020002020), - CONST64(0x0020200020002000), CONST64(0x0020202020002000), CONST64(0x0020200020002020), CONST64(0x0020202020002020), - CONST64(0x0000000020200000), CONST64(0x0000002020200000), CONST64(0x0000000020200020), CONST64(0x0000002020200020), - CONST64(0x0000200020200000), CONST64(0x0000202020200000), CONST64(0x0000200020200020), CONST64(0x0000202020200020), - CONST64(0x0000000020202000), CONST64(0x0000002020202000), CONST64(0x0000000020202020), CONST64(0x0000002020202020), - CONST64(0x0000200020202000), CONST64(0x0000202020202000), CONST64(0x0000200020202020), CONST64(0x0000202020202020), - CONST64(0x0020000020200000), CONST64(0x0020002020200000), CONST64(0x0020000020200020), CONST64(0x0020002020200020), - CONST64(0x0020200020200000), CONST64(0x0020202020200000), CONST64(0x0020200020200020), CONST64(0x0020202020200020), - CONST64(0x0020000020202000), CONST64(0x0020002020202000), CONST64(0x0020000020202020), CONST64(0x0020002020202020), - CONST64(0x0020200020202000), CONST64(0x0020202020202000), CONST64(0x0020200020202020), CONST64(0x0020202020202020), - CONST64(0x2000000020000000), CONST64(0x2000002020000000), CONST64(0x2000000020000020), CONST64(0x2000002020000020), - CONST64(0x2000200020000000), CONST64(0x2000202020000000), CONST64(0x2000200020000020), CONST64(0x2000202020000020), - CONST64(0x2000000020002000), CONST64(0x2000002020002000), CONST64(0x2000000020002020), CONST64(0x2000002020002020), - CONST64(0x2000200020002000), CONST64(0x2000202020002000), CONST64(0x2000200020002020), CONST64(0x2000202020002020), - CONST64(0x2020000020000000), CONST64(0x2020002020000000), CONST64(0x2020000020000020), CONST64(0x2020002020000020), - CONST64(0x2020200020000000), CONST64(0x2020202020000000), CONST64(0x2020200020000020), CONST64(0x2020202020000020), - CONST64(0x2020000020002000), CONST64(0x2020002020002000), CONST64(0x2020000020002020), CONST64(0x2020002020002020), - CONST64(0x2020200020002000), CONST64(0x2020202020002000), CONST64(0x2020200020002020), CONST64(0x2020202020002020), - CONST64(0x2000000020200000), CONST64(0x2000002020200000), CONST64(0x2000000020200020), CONST64(0x2000002020200020), - CONST64(0x2000200020200000), CONST64(0x2000202020200000), CONST64(0x2000200020200020), CONST64(0x2000202020200020), - CONST64(0x2000000020202000), CONST64(0x2000002020202000), CONST64(0x2000000020202020), CONST64(0x2000002020202020), - CONST64(0x2000200020202000), CONST64(0x2000202020202000), CONST64(0x2000200020202020), CONST64(0x2000202020202020), - CONST64(0x2020000020200000), CONST64(0x2020002020200000), CONST64(0x2020000020200020), CONST64(0x2020002020200020), - CONST64(0x2020200020200000), CONST64(0x2020202020200000), CONST64(0x2020200020200020), CONST64(0x2020202020200020), - CONST64(0x2020000020202000), CONST64(0x2020002020202000), CONST64(0x2020000020202020), CONST64(0x2020002020202020), - CONST64(0x2020200020202000), CONST64(0x2020202020202000), CONST64(0x2020200020202020), CONST64(0x2020202020202020) - }}; - -static const ulong64 des_fp[8][256] = { - -{ CONST64(0x0000000000000000), CONST64(0x0000008000000000), CONST64(0x0000000002000000), CONST64(0x0000008002000000), - CONST64(0x0000000000020000), CONST64(0x0000008000020000), CONST64(0x0000000002020000), CONST64(0x0000008002020000), - CONST64(0x0000000000000200), CONST64(0x0000008000000200), CONST64(0x0000000002000200), CONST64(0x0000008002000200), - CONST64(0x0000000000020200), CONST64(0x0000008000020200), CONST64(0x0000000002020200), CONST64(0x0000008002020200), - CONST64(0x0000000000000002), CONST64(0x0000008000000002), CONST64(0x0000000002000002), CONST64(0x0000008002000002), - CONST64(0x0000000000020002), CONST64(0x0000008000020002), CONST64(0x0000000002020002), CONST64(0x0000008002020002), - CONST64(0x0000000000000202), CONST64(0x0000008000000202), CONST64(0x0000000002000202), CONST64(0x0000008002000202), - CONST64(0x0000000000020202), CONST64(0x0000008000020202), CONST64(0x0000000002020202), CONST64(0x0000008002020202), - CONST64(0x0200000000000000), CONST64(0x0200008000000000), CONST64(0x0200000002000000), CONST64(0x0200008002000000), - CONST64(0x0200000000020000), CONST64(0x0200008000020000), CONST64(0x0200000002020000), CONST64(0x0200008002020000), - CONST64(0x0200000000000200), CONST64(0x0200008000000200), CONST64(0x0200000002000200), CONST64(0x0200008002000200), - CONST64(0x0200000000020200), CONST64(0x0200008000020200), CONST64(0x0200000002020200), CONST64(0x0200008002020200), - CONST64(0x0200000000000002), CONST64(0x0200008000000002), CONST64(0x0200000002000002), CONST64(0x0200008002000002), - CONST64(0x0200000000020002), CONST64(0x0200008000020002), CONST64(0x0200000002020002), CONST64(0x0200008002020002), - CONST64(0x0200000000000202), CONST64(0x0200008000000202), CONST64(0x0200000002000202), CONST64(0x0200008002000202), - CONST64(0x0200000000020202), CONST64(0x0200008000020202), CONST64(0x0200000002020202), CONST64(0x0200008002020202), - CONST64(0x0002000000000000), CONST64(0x0002008000000000), CONST64(0x0002000002000000), CONST64(0x0002008002000000), - CONST64(0x0002000000020000), CONST64(0x0002008000020000), CONST64(0x0002000002020000), CONST64(0x0002008002020000), - CONST64(0x0002000000000200), CONST64(0x0002008000000200), CONST64(0x0002000002000200), CONST64(0x0002008002000200), - CONST64(0x0002000000020200), CONST64(0x0002008000020200), CONST64(0x0002000002020200), CONST64(0x0002008002020200), - CONST64(0x0002000000000002), CONST64(0x0002008000000002), CONST64(0x0002000002000002), CONST64(0x0002008002000002), - CONST64(0x0002000000020002), CONST64(0x0002008000020002), CONST64(0x0002000002020002), CONST64(0x0002008002020002), - CONST64(0x0002000000000202), CONST64(0x0002008000000202), CONST64(0x0002000002000202), CONST64(0x0002008002000202), - CONST64(0x0002000000020202), CONST64(0x0002008000020202), CONST64(0x0002000002020202), CONST64(0x0002008002020202), - CONST64(0x0202000000000000), CONST64(0x0202008000000000), CONST64(0x0202000002000000), CONST64(0x0202008002000000), - CONST64(0x0202000000020000), CONST64(0x0202008000020000), CONST64(0x0202000002020000), CONST64(0x0202008002020000), - CONST64(0x0202000000000200), CONST64(0x0202008000000200), CONST64(0x0202000002000200), CONST64(0x0202008002000200), - CONST64(0x0202000000020200), CONST64(0x0202008000020200), CONST64(0x0202000002020200), CONST64(0x0202008002020200), - CONST64(0x0202000000000002), CONST64(0x0202008000000002), CONST64(0x0202000002000002), CONST64(0x0202008002000002), - CONST64(0x0202000000020002), CONST64(0x0202008000020002), CONST64(0x0202000002020002), CONST64(0x0202008002020002), - CONST64(0x0202000000000202), CONST64(0x0202008000000202), CONST64(0x0202000002000202), CONST64(0x0202008002000202), - CONST64(0x0202000000020202), CONST64(0x0202008000020202), CONST64(0x0202000002020202), CONST64(0x0202008002020202), - CONST64(0x0000020000000000), CONST64(0x0000028000000000), CONST64(0x0000020002000000), CONST64(0x0000028002000000), - CONST64(0x0000020000020000), CONST64(0x0000028000020000), CONST64(0x0000020002020000), CONST64(0x0000028002020000), - CONST64(0x0000020000000200), CONST64(0x0000028000000200), CONST64(0x0000020002000200), CONST64(0x0000028002000200), - CONST64(0x0000020000020200), CONST64(0x0000028000020200), CONST64(0x0000020002020200), CONST64(0x0000028002020200), - CONST64(0x0000020000000002), CONST64(0x0000028000000002), CONST64(0x0000020002000002), CONST64(0x0000028002000002), - CONST64(0x0000020000020002), CONST64(0x0000028000020002), CONST64(0x0000020002020002), CONST64(0x0000028002020002), - CONST64(0x0000020000000202), CONST64(0x0000028000000202), CONST64(0x0000020002000202), CONST64(0x0000028002000202), - CONST64(0x0000020000020202), CONST64(0x0000028000020202), CONST64(0x0000020002020202), CONST64(0x0000028002020202), - CONST64(0x0200020000000000), CONST64(0x0200028000000000), CONST64(0x0200020002000000), CONST64(0x0200028002000000), - CONST64(0x0200020000020000), CONST64(0x0200028000020000), CONST64(0x0200020002020000), CONST64(0x0200028002020000), - CONST64(0x0200020000000200), CONST64(0x0200028000000200), CONST64(0x0200020002000200), CONST64(0x0200028002000200), - CONST64(0x0200020000020200), CONST64(0x0200028000020200), CONST64(0x0200020002020200), CONST64(0x0200028002020200), - CONST64(0x0200020000000002), CONST64(0x0200028000000002), CONST64(0x0200020002000002), CONST64(0x0200028002000002), - CONST64(0x0200020000020002), CONST64(0x0200028000020002), CONST64(0x0200020002020002), CONST64(0x0200028002020002), - CONST64(0x0200020000000202), CONST64(0x0200028000000202), CONST64(0x0200020002000202), CONST64(0x0200028002000202), - CONST64(0x0200020000020202), CONST64(0x0200028000020202), CONST64(0x0200020002020202), CONST64(0x0200028002020202), - CONST64(0x0002020000000000), CONST64(0x0002028000000000), CONST64(0x0002020002000000), CONST64(0x0002028002000000), - CONST64(0x0002020000020000), CONST64(0x0002028000020000), CONST64(0x0002020002020000), CONST64(0x0002028002020000), - CONST64(0x0002020000000200), CONST64(0x0002028000000200), CONST64(0x0002020002000200), CONST64(0x0002028002000200), - CONST64(0x0002020000020200), CONST64(0x0002028000020200), CONST64(0x0002020002020200), CONST64(0x0002028002020200), - CONST64(0x0002020000000002), CONST64(0x0002028000000002), CONST64(0x0002020002000002), CONST64(0x0002028002000002), - CONST64(0x0002020000020002), CONST64(0x0002028000020002), CONST64(0x0002020002020002), CONST64(0x0002028002020002), - CONST64(0x0002020000000202), CONST64(0x0002028000000202), CONST64(0x0002020002000202), CONST64(0x0002028002000202), - CONST64(0x0002020000020202), CONST64(0x0002028000020202), CONST64(0x0002020002020202), CONST64(0x0002028002020202), - CONST64(0x0202020000000000), CONST64(0x0202028000000000), CONST64(0x0202020002000000), CONST64(0x0202028002000000), - CONST64(0x0202020000020000), CONST64(0x0202028000020000), CONST64(0x0202020002020000), CONST64(0x0202028002020000), - CONST64(0x0202020000000200), CONST64(0x0202028000000200), CONST64(0x0202020002000200), CONST64(0x0202028002000200), - CONST64(0x0202020000020200), CONST64(0x0202028000020200), CONST64(0x0202020002020200), CONST64(0x0202028002020200), - CONST64(0x0202020000000002), CONST64(0x0202028000000002), CONST64(0x0202020002000002), CONST64(0x0202028002000002), - CONST64(0x0202020000020002), CONST64(0x0202028000020002), CONST64(0x0202020002020002), CONST64(0x0202028002020002), - CONST64(0x0202020000000202), CONST64(0x0202028000000202), CONST64(0x0202020002000202), CONST64(0x0202028002000202), - CONST64(0x0202020000020202), CONST64(0x0202028000020202), CONST64(0x0202020002020202), CONST64(0x0202028002020202) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000000200000000), CONST64(0x0000000008000000), CONST64(0x0000000208000000), - CONST64(0x0000000000080000), CONST64(0x0000000200080000), CONST64(0x0000000008080000), CONST64(0x0000000208080000), - CONST64(0x0000000000000800), CONST64(0x0000000200000800), CONST64(0x0000000008000800), CONST64(0x0000000208000800), - CONST64(0x0000000000080800), CONST64(0x0000000200080800), CONST64(0x0000000008080800), CONST64(0x0000000208080800), - CONST64(0x0000000000000008), CONST64(0x0000000200000008), CONST64(0x0000000008000008), CONST64(0x0000000208000008), - CONST64(0x0000000000080008), CONST64(0x0000000200080008), CONST64(0x0000000008080008), CONST64(0x0000000208080008), - CONST64(0x0000000000000808), CONST64(0x0000000200000808), CONST64(0x0000000008000808), CONST64(0x0000000208000808), - CONST64(0x0000000000080808), CONST64(0x0000000200080808), CONST64(0x0000000008080808), CONST64(0x0000000208080808), - CONST64(0x0800000000000000), CONST64(0x0800000200000000), CONST64(0x0800000008000000), CONST64(0x0800000208000000), - CONST64(0x0800000000080000), CONST64(0x0800000200080000), CONST64(0x0800000008080000), CONST64(0x0800000208080000), - CONST64(0x0800000000000800), CONST64(0x0800000200000800), CONST64(0x0800000008000800), CONST64(0x0800000208000800), - CONST64(0x0800000000080800), CONST64(0x0800000200080800), CONST64(0x0800000008080800), CONST64(0x0800000208080800), - CONST64(0x0800000000000008), CONST64(0x0800000200000008), CONST64(0x0800000008000008), CONST64(0x0800000208000008), - CONST64(0x0800000000080008), CONST64(0x0800000200080008), CONST64(0x0800000008080008), CONST64(0x0800000208080008), - CONST64(0x0800000000000808), CONST64(0x0800000200000808), CONST64(0x0800000008000808), CONST64(0x0800000208000808), - CONST64(0x0800000000080808), CONST64(0x0800000200080808), CONST64(0x0800000008080808), CONST64(0x0800000208080808), - CONST64(0x0008000000000000), CONST64(0x0008000200000000), CONST64(0x0008000008000000), CONST64(0x0008000208000000), - CONST64(0x0008000000080000), CONST64(0x0008000200080000), CONST64(0x0008000008080000), CONST64(0x0008000208080000), - CONST64(0x0008000000000800), CONST64(0x0008000200000800), CONST64(0x0008000008000800), CONST64(0x0008000208000800), - CONST64(0x0008000000080800), CONST64(0x0008000200080800), CONST64(0x0008000008080800), CONST64(0x0008000208080800), - CONST64(0x0008000000000008), CONST64(0x0008000200000008), CONST64(0x0008000008000008), CONST64(0x0008000208000008), - CONST64(0x0008000000080008), CONST64(0x0008000200080008), CONST64(0x0008000008080008), CONST64(0x0008000208080008), - CONST64(0x0008000000000808), CONST64(0x0008000200000808), CONST64(0x0008000008000808), CONST64(0x0008000208000808), - CONST64(0x0008000000080808), CONST64(0x0008000200080808), CONST64(0x0008000008080808), CONST64(0x0008000208080808), - CONST64(0x0808000000000000), CONST64(0x0808000200000000), CONST64(0x0808000008000000), CONST64(0x0808000208000000), - CONST64(0x0808000000080000), CONST64(0x0808000200080000), CONST64(0x0808000008080000), CONST64(0x0808000208080000), - CONST64(0x0808000000000800), CONST64(0x0808000200000800), CONST64(0x0808000008000800), CONST64(0x0808000208000800), - CONST64(0x0808000000080800), CONST64(0x0808000200080800), CONST64(0x0808000008080800), CONST64(0x0808000208080800), - CONST64(0x0808000000000008), CONST64(0x0808000200000008), CONST64(0x0808000008000008), CONST64(0x0808000208000008), - CONST64(0x0808000000080008), CONST64(0x0808000200080008), CONST64(0x0808000008080008), CONST64(0x0808000208080008), - CONST64(0x0808000000000808), CONST64(0x0808000200000808), CONST64(0x0808000008000808), CONST64(0x0808000208000808), - CONST64(0x0808000000080808), CONST64(0x0808000200080808), CONST64(0x0808000008080808), CONST64(0x0808000208080808), - CONST64(0x0000080000000000), CONST64(0x0000080200000000), CONST64(0x0000080008000000), CONST64(0x0000080208000000), - CONST64(0x0000080000080000), CONST64(0x0000080200080000), CONST64(0x0000080008080000), CONST64(0x0000080208080000), - CONST64(0x0000080000000800), CONST64(0x0000080200000800), CONST64(0x0000080008000800), CONST64(0x0000080208000800), - CONST64(0x0000080000080800), CONST64(0x0000080200080800), CONST64(0x0000080008080800), CONST64(0x0000080208080800), - CONST64(0x0000080000000008), CONST64(0x0000080200000008), CONST64(0x0000080008000008), CONST64(0x0000080208000008), - CONST64(0x0000080000080008), CONST64(0x0000080200080008), CONST64(0x0000080008080008), CONST64(0x0000080208080008), - CONST64(0x0000080000000808), CONST64(0x0000080200000808), CONST64(0x0000080008000808), CONST64(0x0000080208000808), - CONST64(0x0000080000080808), CONST64(0x0000080200080808), CONST64(0x0000080008080808), CONST64(0x0000080208080808), - CONST64(0x0800080000000000), CONST64(0x0800080200000000), CONST64(0x0800080008000000), CONST64(0x0800080208000000), - CONST64(0x0800080000080000), CONST64(0x0800080200080000), CONST64(0x0800080008080000), CONST64(0x0800080208080000), - CONST64(0x0800080000000800), CONST64(0x0800080200000800), CONST64(0x0800080008000800), CONST64(0x0800080208000800), - CONST64(0x0800080000080800), CONST64(0x0800080200080800), CONST64(0x0800080008080800), CONST64(0x0800080208080800), - CONST64(0x0800080000000008), CONST64(0x0800080200000008), CONST64(0x0800080008000008), CONST64(0x0800080208000008), - CONST64(0x0800080000080008), CONST64(0x0800080200080008), CONST64(0x0800080008080008), CONST64(0x0800080208080008), - CONST64(0x0800080000000808), CONST64(0x0800080200000808), CONST64(0x0800080008000808), CONST64(0x0800080208000808), - CONST64(0x0800080000080808), CONST64(0x0800080200080808), CONST64(0x0800080008080808), CONST64(0x0800080208080808), - CONST64(0x0008080000000000), CONST64(0x0008080200000000), CONST64(0x0008080008000000), CONST64(0x0008080208000000), - CONST64(0x0008080000080000), CONST64(0x0008080200080000), CONST64(0x0008080008080000), CONST64(0x0008080208080000), - CONST64(0x0008080000000800), CONST64(0x0008080200000800), CONST64(0x0008080008000800), CONST64(0x0008080208000800), - CONST64(0x0008080000080800), CONST64(0x0008080200080800), CONST64(0x0008080008080800), CONST64(0x0008080208080800), - CONST64(0x0008080000000008), CONST64(0x0008080200000008), CONST64(0x0008080008000008), CONST64(0x0008080208000008), - CONST64(0x0008080000080008), CONST64(0x0008080200080008), CONST64(0x0008080008080008), CONST64(0x0008080208080008), - CONST64(0x0008080000000808), CONST64(0x0008080200000808), CONST64(0x0008080008000808), CONST64(0x0008080208000808), - CONST64(0x0008080000080808), CONST64(0x0008080200080808), CONST64(0x0008080008080808), CONST64(0x0008080208080808), - CONST64(0x0808080000000000), CONST64(0x0808080200000000), CONST64(0x0808080008000000), CONST64(0x0808080208000000), - CONST64(0x0808080000080000), CONST64(0x0808080200080000), CONST64(0x0808080008080000), CONST64(0x0808080208080000), - CONST64(0x0808080000000800), CONST64(0x0808080200000800), CONST64(0x0808080008000800), CONST64(0x0808080208000800), - CONST64(0x0808080000080800), CONST64(0x0808080200080800), CONST64(0x0808080008080800), CONST64(0x0808080208080800), - CONST64(0x0808080000000008), CONST64(0x0808080200000008), CONST64(0x0808080008000008), CONST64(0x0808080208000008), - CONST64(0x0808080000080008), CONST64(0x0808080200080008), CONST64(0x0808080008080008), CONST64(0x0808080208080008), - CONST64(0x0808080000000808), CONST64(0x0808080200000808), CONST64(0x0808080008000808), CONST64(0x0808080208000808), - CONST64(0x0808080000080808), CONST64(0x0808080200080808), CONST64(0x0808080008080808), CONST64(0x0808080208080808) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000000800000000), CONST64(0x0000000020000000), CONST64(0x0000000820000000), - CONST64(0x0000000000200000), CONST64(0x0000000800200000), CONST64(0x0000000020200000), CONST64(0x0000000820200000), - CONST64(0x0000000000002000), CONST64(0x0000000800002000), CONST64(0x0000000020002000), CONST64(0x0000000820002000), - CONST64(0x0000000000202000), CONST64(0x0000000800202000), CONST64(0x0000000020202000), CONST64(0x0000000820202000), - CONST64(0x0000000000000020), CONST64(0x0000000800000020), CONST64(0x0000000020000020), CONST64(0x0000000820000020), - CONST64(0x0000000000200020), CONST64(0x0000000800200020), CONST64(0x0000000020200020), CONST64(0x0000000820200020), - CONST64(0x0000000000002020), CONST64(0x0000000800002020), CONST64(0x0000000020002020), CONST64(0x0000000820002020), - CONST64(0x0000000000202020), CONST64(0x0000000800202020), CONST64(0x0000000020202020), CONST64(0x0000000820202020), - CONST64(0x2000000000000000), CONST64(0x2000000800000000), CONST64(0x2000000020000000), CONST64(0x2000000820000000), - CONST64(0x2000000000200000), CONST64(0x2000000800200000), CONST64(0x2000000020200000), CONST64(0x2000000820200000), - CONST64(0x2000000000002000), CONST64(0x2000000800002000), CONST64(0x2000000020002000), CONST64(0x2000000820002000), - CONST64(0x2000000000202000), CONST64(0x2000000800202000), CONST64(0x2000000020202000), CONST64(0x2000000820202000), - CONST64(0x2000000000000020), CONST64(0x2000000800000020), CONST64(0x2000000020000020), CONST64(0x2000000820000020), - CONST64(0x2000000000200020), CONST64(0x2000000800200020), CONST64(0x2000000020200020), CONST64(0x2000000820200020), - CONST64(0x2000000000002020), CONST64(0x2000000800002020), CONST64(0x2000000020002020), CONST64(0x2000000820002020), - CONST64(0x2000000000202020), CONST64(0x2000000800202020), CONST64(0x2000000020202020), CONST64(0x2000000820202020), - CONST64(0x0020000000000000), CONST64(0x0020000800000000), CONST64(0x0020000020000000), CONST64(0x0020000820000000), - CONST64(0x0020000000200000), CONST64(0x0020000800200000), CONST64(0x0020000020200000), CONST64(0x0020000820200000), - CONST64(0x0020000000002000), CONST64(0x0020000800002000), CONST64(0x0020000020002000), CONST64(0x0020000820002000), - CONST64(0x0020000000202000), CONST64(0x0020000800202000), CONST64(0x0020000020202000), CONST64(0x0020000820202000), - CONST64(0x0020000000000020), CONST64(0x0020000800000020), CONST64(0x0020000020000020), CONST64(0x0020000820000020), - CONST64(0x0020000000200020), CONST64(0x0020000800200020), CONST64(0x0020000020200020), CONST64(0x0020000820200020), - CONST64(0x0020000000002020), CONST64(0x0020000800002020), CONST64(0x0020000020002020), CONST64(0x0020000820002020), - CONST64(0x0020000000202020), CONST64(0x0020000800202020), CONST64(0x0020000020202020), CONST64(0x0020000820202020), - CONST64(0x2020000000000000), CONST64(0x2020000800000000), CONST64(0x2020000020000000), CONST64(0x2020000820000000), - CONST64(0x2020000000200000), CONST64(0x2020000800200000), CONST64(0x2020000020200000), CONST64(0x2020000820200000), - CONST64(0x2020000000002000), CONST64(0x2020000800002000), CONST64(0x2020000020002000), CONST64(0x2020000820002000), - CONST64(0x2020000000202000), CONST64(0x2020000800202000), CONST64(0x2020000020202000), CONST64(0x2020000820202000), - CONST64(0x2020000000000020), CONST64(0x2020000800000020), CONST64(0x2020000020000020), CONST64(0x2020000820000020), - CONST64(0x2020000000200020), CONST64(0x2020000800200020), CONST64(0x2020000020200020), CONST64(0x2020000820200020), - CONST64(0x2020000000002020), CONST64(0x2020000800002020), CONST64(0x2020000020002020), CONST64(0x2020000820002020), - CONST64(0x2020000000202020), CONST64(0x2020000800202020), CONST64(0x2020000020202020), CONST64(0x2020000820202020), - CONST64(0x0000200000000000), CONST64(0x0000200800000000), CONST64(0x0000200020000000), CONST64(0x0000200820000000), - CONST64(0x0000200000200000), CONST64(0x0000200800200000), CONST64(0x0000200020200000), CONST64(0x0000200820200000), - CONST64(0x0000200000002000), CONST64(0x0000200800002000), CONST64(0x0000200020002000), CONST64(0x0000200820002000), - CONST64(0x0000200000202000), CONST64(0x0000200800202000), CONST64(0x0000200020202000), CONST64(0x0000200820202000), - CONST64(0x0000200000000020), CONST64(0x0000200800000020), CONST64(0x0000200020000020), CONST64(0x0000200820000020), - CONST64(0x0000200000200020), CONST64(0x0000200800200020), CONST64(0x0000200020200020), CONST64(0x0000200820200020), - CONST64(0x0000200000002020), CONST64(0x0000200800002020), CONST64(0x0000200020002020), CONST64(0x0000200820002020), - CONST64(0x0000200000202020), CONST64(0x0000200800202020), CONST64(0x0000200020202020), CONST64(0x0000200820202020), - CONST64(0x2000200000000000), CONST64(0x2000200800000000), CONST64(0x2000200020000000), CONST64(0x2000200820000000), - CONST64(0x2000200000200000), CONST64(0x2000200800200000), CONST64(0x2000200020200000), CONST64(0x2000200820200000), - CONST64(0x2000200000002000), CONST64(0x2000200800002000), CONST64(0x2000200020002000), CONST64(0x2000200820002000), - CONST64(0x2000200000202000), CONST64(0x2000200800202000), CONST64(0x2000200020202000), CONST64(0x2000200820202000), - CONST64(0x2000200000000020), CONST64(0x2000200800000020), CONST64(0x2000200020000020), CONST64(0x2000200820000020), - CONST64(0x2000200000200020), CONST64(0x2000200800200020), CONST64(0x2000200020200020), CONST64(0x2000200820200020), - CONST64(0x2000200000002020), CONST64(0x2000200800002020), CONST64(0x2000200020002020), CONST64(0x2000200820002020), - CONST64(0x2000200000202020), CONST64(0x2000200800202020), CONST64(0x2000200020202020), CONST64(0x2000200820202020), - CONST64(0x0020200000000000), CONST64(0x0020200800000000), CONST64(0x0020200020000000), CONST64(0x0020200820000000), - CONST64(0x0020200000200000), CONST64(0x0020200800200000), CONST64(0x0020200020200000), CONST64(0x0020200820200000), - CONST64(0x0020200000002000), CONST64(0x0020200800002000), CONST64(0x0020200020002000), CONST64(0x0020200820002000), - CONST64(0x0020200000202000), CONST64(0x0020200800202000), CONST64(0x0020200020202000), CONST64(0x0020200820202000), - CONST64(0x0020200000000020), CONST64(0x0020200800000020), CONST64(0x0020200020000020), CONST64(0x0020200820000020), - CONST64(0x0020200000200020), CONST64(0x0020200800200020), CONST64(0x0020200020200020), CONST64(0x0020200820200020), - CONST64(0x0020200000002020), CONST64(0x0020200800002020), CONST64(0x0020200020002020), CONST64(0x0020200820002020), - CONST64(0x0020200000202020), CONST64(0x0020200800202020), CONST64(0x0020200020202020), CONST64(0x0020200820202020), - CONST64(0x2020200000000000), CONST64(0x2020200800000000), CONST64(0x2020200020000000), CONST64(0x2020200820000000), - CONST64(0x2020200000200000), CONST64(0x2020200800200000), CONST64(0x2020200020200000), CONST64(0x2020200820200000), - CONST64(0x2020200000002000), CONST64(0x2020200800002000), CONST64(0x2020200020002000), CONST64(0x2020200820002000), - CONST64(0x2020200000202000), CONST64(0x2020200800202000), CONST64(0x2020200020202000), CONST64(0x2020200820202000), - CONST64(0x2020200000000020), CONST64(0x2020200800000020), CONST64(0x2020200020000020), CONST64(0x2020200820000020), - CONST64(0x2020200000200020), CONST64(0x2020200800200020), CONST64(0x2020200020200020), CONST64(0x2020200820200020), - CONST64(0x2020200000002020), CONST64(0x2020200800002020), CONST64(0x2020200020002020), CONST64(0x2020200820002020), - CONST64(0x2020200000202020), CONST64(0x2020200800202020), CONST64(0x2020200020202020), CONST64(0x2020200820202020) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000002000000000), CONST64(0x0000000080000000), CONST64(0x0000002080000000), - CONST64(0x0000000000800000), CONST64(0x0000002000800000), CONST64(0x0000000080800000), CONST64(0x0000002080800000), - CONST64(0x0000000000008000), CONST64(0x0000002000008000), CONST64(0x0000000080008000), CONST64(0x0000002080008000), - CONST64(0x0000000000808000), CONST64(0x0000002000808000), CONST64(0x0000000080808000), CONST64(0x0000002080808000), - CONST64(0x0000000000000080), CONST64(0x0000002000000080), CONST64(0x0000000080000080), CONST64(0x0000002080000080), - CONST64(0x0000000000800080), CONST64(0x0000002000800080), CONST64(0x0000000080800080), CONST64(0x0000002080800080), - CONST64(0x0000000000008080), CONST64(0x0000002000008080), CONST64(0x0000000080008080), CONST64(0x0000002080008080), - CONST64(0x0000000000808080), CONST64(0x0000002000808080), CONST64(0x0000000080808080), CONST64(0x0000002080808080), - CONST64(0x8000000000000000), CONST64(0x8000002000000000), CONST64(0x8000000080000000), CONST64(0x8000002080000000), - CONST64(0x8000000000800000), CONST64(0x8000002000800000), CONST64(0x8000000080800000), CONST64(0x8000002080800000), - CONST64(0x8000000000008000), CONST64(0x8000002000008000), CONST64(0x8000000080008000), CONST64(0x8000002080008000), - CONST64(0x8000000000808000), CONST64(0x8000002000808000), CONST64(0x8000000080808000), CONST64(0x8000002080808000), - CONST64(0x8000000000000080), CONST64(0x8000002000000080), CONST64(0x8000000080000080), CONST64(0x8000002080000080), - CONST64(0x8000000000800080), CONST64(0x8000002000800080), CONST64(0x8000000080800080), CONST64(0x8000002080800080), - CONST64(0x8000000000008080), CONST64(0x8000002000008080), CONST64(0x8000000080008080), CONST64(0x8000002080008080), - CONST64(0x8000000000808080), CONST64(0x8000002000808080), CONST64(0x8000000080808080), CONST64(0x8000002080808080), - CONST64(0x0080000000000000), CONST64(0x0080002000000000), CONST64(0x0080000080000000), CONST64(0x0080002080000000), - CONST64(0x0080000000800000), CONST64(0x0080002000800000), CONST64(0x0080000080800000), CONST64(0x0080002080800000), - CONST64(0x0080000000008000), CONST64(0x0080002000008000), CONST64(0x0080000080008000), CONST64(0x0080002080008000), - CONST64(0x0080000000808000), CONST64(0x0080002000808000), CONST64(0x0080000080808000), CONST64(0x0080002080808000), - CONST64(0x0080000000000080), CONST64(0x0080002000000080), CONST64(0x0080000080000080), CONST64(0x0080002080000080), - CONST64(0x0080000000800080), CONST64(0x0080002000800080), CONST64(0x0080000080800080), CONST64(0x0080002080800080), - CONST64(0x0080000000008080), CONST64(0x0080002000008080), CONST64(0x0080000080008080), CONST64(0x0080002080008080), - CONST64(0x0080000000808080), CONST64(0x0080002000808080), CONST64(0x0080000080808080), CONST64(0x0080002080808080), - CONST64(0x8080000000000000), CONST64(0x8080002000000000), CONST64(0x8080000080000000), CONST64(0x8080002080000000), - CONST64(0x8080000000800000), CONST64(0x8080002000800000), CONST64(0x8080000080800000), CONST64(0x8080002080800000), - CONST64(0x8080000000008000), CONST64(0x8080002000008000), CONST64(0x8080000080008000), CONST64(0x8080002080008000), - CONST64(0x8080000000808000), CONST64(0x8080002000808000), CONST64(0x8080000080808000), CONST64(0x8080002080808000), - CONST64(0x8080000000000080), CONST64(0x8080002000000080), CONST64(0x8080000080000080), CONST64(0x8080002080000080), - CONST64(0x8080000000800080), CONST64(0x8080002000800080), CONST64(0x8080000080800080), CONST64(0x8080002080800080), - CONST64(0x8080000000008080), CONST64(0x8080002000008080), CONST64(0x8080000080008080), CONST64(0x8080002080008080), - CONST64(0x8080000000808080), CONST64(0x8080002000808080), CONST64(0x8080000080808080), CONST64(0x8080002080808080), - CONST64(0x0000800000000000), CONST64(0x0000802000000000), CONST64(0x0000800080000000), CONST64(0x0000802080000000), - CONST64(0x0000800000800000), CONST64(0x0000802000800000), CONST64(0x0000800080800000), CONST64(0x0000802080800000), - CONST64(0x0000800000008000), CONST64(0x0000802000008000), CONST64(0x0000800080008000), CONST64(0x0000802080008000), - CONST64(0x0000800000808000), CONST64(0x0000802000808000), CONST64(0x0000800080808000), CONST64(0x0000802080808000), - CONST64(0x0000800000000080), CONST64(0x0000802000000080), CONST64(0x0000800080000080), CONST64(0x0000802080000080), - CONST64(0x0000800000800080), CONST64(0x0000802000800080), CONST64(0x0000800080800080), CONST64(0x0000802080800080), - CONST64(0x0000800000008080), CONST64(0x0000802000008080), CONST64(0x0000800080008080), CONST64(0x0000802080008080), - CONST64(0x0000800000808080), CONST64(0x0000802000808080), CONST64(0x0000800080808080), CONST64(0x0000802080808080), - CONST64(0x8000800000000000), CONST64(0x8000802000000000), CONST64(0x8000800080000000), CONST64(0x8000802080000000), - CONST64(0x8000800000800000), CONST64(0x8000802000800000), CONST64(0x8000800080800000), CONST64(0x8000802080800000), - CONST64(0x8000800000008000), CONST64(0x8000802000008000), CONST64(0x8000800080008000), CONST64(0x8000802080008000), - CONST64(0x8000800000808000), CONST64(0x8000802000808000), CONST64(0x8000800080808000), CONST64(0x8000802080808000), - CONST64(0x8000800000000080), CONST64(0x8000802000000080), CONST64(0x8000800080000080), CONST64(0x8000802080000080), - CONST64(0x8000800000800080), CONST64(0x8000802000800080), CONST64(0x8000800080800080), CONST64(0x8000802080800080), - CONST64(0x8000800000008080), CONST64(0x8000802000008080), CONST64(0x8000800080008080), CONST64(0x8000802080008080), - CONST64(0x8000800000808080), CONST64(0x8000802000808080), CONST64(0x8000800080808080), CONST64(0x8000802080808080), - CONST64(0x0080800000000000), CONST64(0x0080802000000000), CONST64(0x0080800080000000), CONST64(0x0080802080000000), - CONST64(0x0080800000800000), CONST64(0x0080802000800000), CONST64(0x0080800080800000), CONST64(0x0080802080800000), - CONST64(0x0080800000008000), CONST64(0x0080802000008000), CONST64(0x0080800080008000), CONST64(0x0080802080008000), - CONST64(0x0080800000808000), CONST64(0x0080802000808000), CONST64(0x0080800080808000), CONST64(0x0080802080808000), - CONST64(0x0080800000000080), CONST64(0x0080802000000080), CONST64(0x0080800080000080), CONST64(0x0080802080000080), - CONST64(0x0080800000800080), CONST64(0x0080802000800080), CONST64(0x0080800080800080), CONST64(0x0080802080800080), - CONST64(0x0080800000008080), CONST64(0x0080802000008080), CONST64(0x0080800080008080), CONST64(0x0080802080008080), - CONST64(0x0080800000808080), CONST64(0x0080802000808080), CONST64(0x0080800080808080), CONST64(0x0080802080808080), - CONST64(0x8080800000000000), CONST64(0x8080802000000000), CONST64(0x8080800080000000), CONST64(0x8080802080000000), - CONST64(0x8080800000800000), CONST64(0x8080802000800000), CONST64(0x8080800080800000), CONST64(0x8080802080800000), - CONST64(0x8080800000008000), CONST64(0x8080802000008000), CONST64(0x8080800080008000), CONST64(0x8080802080008000), - CONST64(0x8080800000808000), CONST64(0x8080802000808000), CONST64(0x8080800080808000), CONST64(0x8080802080808000), - CONST64(0x8080800000000080), CONST64(0x8080802000000080), CONST64(0x8080800080000080), CONST64(0x8080802080000080), - CONST64(0x8080800000800080), CONST64(0x8080802000800080), CONST64(0x8080800080800080), CONST64(0x8080802080800080), - CONST64(0x8080800000008080), CONST64(0x8080802000008080), CONST64(0x8080800080008080), CONST64(0x8080802080008080), - CONST64(0x8080800000808080), CONST64(0x8080802000808080), CONST64(0x8080800080808080), CONST64(0x8080802080808080) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000004000000000), CONST64(0x0000000001000000), CONST64(0x0000004001000000), - CONST64(0x0000000000010000), CONST64(0x0000004000010000), CONST64(0x0000000001010000), CONST64(0x0000004001010000), - CONST64(0x0000000000000100), CONST64(0x0000004000000100), CONST64(0x0000000001000100), CONST64(0x0000004001000100), - CONST64(0x0000000000010100), CONST64(0x0000004000010100), CONST64(0x0000000001010100), CONST64(0x0000004001010100), - CONST64(0x0000000000000001), CONST64(0x0000004000000001), CONST64(0x0000000001000001), CONST64(0x0000004001000001), - CONST64(0x0000000000010001), CONST64(0x0000004000010001), CONST64(0x0000000001010001), CONST64(0x0000004001010001), - CONST64(0x0000000000000101), CONST64(0x0000004000000101), CONST64(0x0000000001000101), CONST64(0x0000004001000101), - CONST64(0x0000000000010101), CONST64(0x0000004000010101), CONST64(0x0000000001010101), CONST64(0x0000004001010101), - CONST64(0x0100000000000000), CONST64(0x0100004000000000), CONST64(0x0100000001000000), CONST64(0x0100004001000000), - CONST64(0x0100000000010000), CONST64(0x0100004000010000), CONST64(0x0100000001010000), CONST64(0x0100004001010000), - CONST64(0x0100000000000100), CONST64(0x0100004000000100), CONST64(0x0100000001000100), CONST64(0x0100004001000100), - CONST64(0x0100000000010100), CONST64(0x0100004000010100), CONST64(0x0100000001010100), CONST64(0x0100004001010100), - CONST64(0x0100000000000001), CONST64(0x0100004000000001), CONST64(0x0100000001000001), CONST64(0x0100004001000001), - CONST64(0x0100000000010001), CONST64(0x0100004000010001), CONST64(0x0100000001010001), CONST64(0x0100004001010001), - CONST64(0x0100000000000101), CONST64(0x0100004000000101), CONST64(0x0100000001000101), CONST64(0x0100004001000101), - CONST64(0x0100000000010101), CONST64(0x0100004000010101), CONST64(0x0100000001010101), CONST64(0x0100004001010101), - CONST64(0x0001000000000000), CONST64(0x0001004000000000), CONST64(0x0001000001000000), CONST64(0x0001004001000000), - CONST64(0x0001000000010000), CONST64(0x0001004000010000), CONST64(0x0001000001010000), CONST64(0x0001004001010000), - CONST64(0x0001000000000100), CONST64(0x0001004000000100), CONST64(0x0001000001000100), CONST64(0x0001004001000100), - CONST64(0x0001000000010100), CONST64(0x0001004000010100), CONST64(0x0001000001010100), CONST64(0x0001004001010100), - CONST64(0x0001000000000001), CONST64(0x0001004000000001), CONST64(0x0001000001000001), CONST64(0x0001004001000001), - CONST64(0x0001000000010001), CONST64(0x0001004000010001), CONST64(0x0001000001010001), CONST64(0x0001004001010001), - CONST64(0x0001000000000101), CONST64(0x0001004000000101), CONST64(0x0001000001000101), CONST64(0x0001004001000101), - CONST64(0x0001000000010101), CONST64(0x0001004000010101), CONST64(0x0001000001010101), CONST64(0x0001004001010101), - CONST64(0x0101000000000000), CONST64(0x0101004000000000), CONST64(0x0101000001000000), CONST64(0x0101004001000000), - CONST64(0x0101000000010000), CONST64(0x0101004000010000), CONST64(0x0101000001010000), CONST64(0x0101004001010000), - CONST64(0x0101000000000100), CONST64(0x0101004000000100), CONST64(0x0101000001000100), CONST64(0x0101004001000100), - CONST64(0x0101000000010100), CONST64(0x0101004000010100), CONST64(0x0101000001010100), CONST64(0x0101004001010100), - CONST64(0x0101000000000001), CONST64(0x0101004000000001), CONST64(0x0101000001000001), CONST64(0x0101004001000001), - CONST64(0x0101000000010001), CONST64(0x0101004000010001), CONST64(0x0101000001010001), CONST64(0x0101004001010001), - CONST64(0x0101000000000101), CONST64(0x0101004000000101), CONST64(0x0101000001000101), CONST64(0x0101004001000101), - CONST64(0x0101000000010101), CONST64(0x0101004000010101), CONST64(0x0101000001010101), CONST64(0x0101004001010101), - CONST64(0x0000010000000000), CONST64(0x0000014000000000), CONST64(0x0000010001000000), CONST64(0x0000014001000000), - CONST64(0x0000010000010000), CONST64(0x0000014000010000), CONST64(0x0000010001010000), CONST64(0x0000014001010000), - CONST64(0x0000010000000100), CONST64(0x0000014000000100), CONST64(0x0000010001000100), CONST64(0x0000014001000100), - CONST64(0x0000010000010100), CONST64(0x0000014000010100), CONST64(0x0000010001010100), CONST64(0x0000014001010100), - CONST64(0x0000010000000001), CONST64(0x0000014000000001), CONST64(0x0000010001000001), CONST64(0x0000014001000001), - CONST64(0x0000010000010001), CONST64(0x0000014000010001), CONST64(0x0000010001010001), CONST64(0x0000014001010001), - CONST64(0x0000010000000101), CONST64(0x0000014000000101), CONST64(0x0000010001000101), CONST64(0x0000014001000101), - CONST64(0x0000010000010101), CONST64(0x0000014000010101), CONST64(0x0000010001010101), CONST64(0x0000014001010101), - CONST64(0x0100010000000000), CONST64(0x0100014000000000), CONST64(0x0100010001000000), CONST64(0x0100014001000000), - CONST64(0x0100010000010000), CONST64(0x0100014000010000), CONST64(0x0100010001010000), CONST64(0x0100014001010000), - CONST64(0x0100010000000100), CONST64(0x0100014000000100), CONST64(0x0100010001000100), CONST64(0x0100014001000100), - CONST64(0x0100010000010100), CONST64(0x0100014000010100), CONST64(0x0100010001010100), CONST64(0x0100014001010100), - CONST64(0x0100010000000001), CONST64(0x0100014000000001), CONST64(0x0100010001000001), CONST64(0x0100014001000001), - CONST64(0x0100010000010001), CONST64(0x0100014000010001), CONST64(0x0100010001010001), CONST64(0x0100014001010001), - CONST64(0x0100010000000101), CONST64(0x0100014000000101), CONST64(0x0100010001000101), CONST64(0x0100014001000101), - CONST64(0x0100010000010101), CONST64(0x0100014000010101), CONST64(0x0100010001010101), CONST64(0x0100014001010101), - CONST64(0x0001010000000000), CONST64(0x0001014000000000), CONST64(0x0001010001000000), CONST64(0x0001014001000000), - CONST64(0x0001010000010000), CONST64(0x0001014000010000), CONST64(0x0001010001010000), CONST64(0x0001014001010000), - CONST64(0x0001010000000100), CONST64(0x0001014000000100), CONST64(0x0001010001000100), CONST64(0x0001014001000100), - CONST64(0x0001010000010100), CONST64(0x0001014000010100), CONST64(0x0001010001010100), CONST64(0x0001014001010100), - CONST64(0x0001010000000001), CONST64(0x0001014000000001), CONST64(0x0001010001000001), CONST64(0x0001014001000001), - CONST64(0x0001010000010001), CONST64(0x0001014000010001), CONST64(0x0001010001010001), CONST64(0x0001014001010001), - CONST64(0x0001010000000101), CONST64(0x0001014000000101), CONST64(0x0001010001000101), CONST64(0x0001014001000101), - CONST64(0x0001010000010101), CONST64(0x0001014000010101), CONST64(0x0001010001010101), CONST64(0x0001014001010101), - CONST64(0x0101010000000000), CONST64(0x0101014000000000), CONST64(0x0101010001000000), CONST64(0x0101014001000000), - CONST64(0x0101010000010000), CONST64(0x0101014000010000), CONST64(0x0101010001010000), CONST64(0x0101014001010000), - CONST64(0x0101010000000100), CONST64(0x0101014000000100), CONST64(0x0101010001000100), CONST64(0x0101014001000100), - CONST64(0x0101010000010100), CONST64(0x0101014000010100), CONST64(0x0101010001010100), CONST64(0x0101014001010100), - CONST64(0x0101010000000001), CONST64(0x0101014000000001), CONST64(0x0101010001000001), CONST64(0x0101014001000001), - CONST64(0x0101010000010001), CONST64(0x0101014000010001), CONST64(0x0101010001010001), CONST64(0x0101014001010001), - CONST64(0x0101010000000101), CONST64(0x0101014000000101), CONST64(0x0101010001000101), CONST64(0x0101014001000101), - CONST64(0x0101010000010101), CONST64(0x0101014000010101), CONST64(0x0101010001010101), CONST64(0x0101014001010101) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000000100000000), CONST64(0x0000000004000000), CONST64(0x0000000104000000), - CONST64(0x0000000000040000), CONST64(0x0000000100040000), CONST64(0x0000000004040000), CONST64(0x0000000104040000), - CONST64(0x0000000000000400), CONST64(0x0000000100000400), CONST64(0x0000000004000400), CONST64(0x0000000104000400), - CONST64(0x0000000000040400), CONST64(0x0000000100040400), CONST64(0x0000000004040400), CONST64(0x0000000104040400), - CONST64(0x0000000000000004), CONST64(0x0000000100000004), CONST64(0x0000000004000004), CONST64(0x0000000104000004), - CONST64(0x0000000000040004), CONST64(0x0000000100040004), CONST64(0x0000000004040004), CONST64(0x0000000104040004), - CONST64(0x0000000000000404), CONST64(0x0000000100000404), CONST64(0x0000000004000404), CONST64(0x0000000104000404), - CONST64(0x0000000000040404), CONST64(0x0000000100040404), CONST64(0x0000000004040404), CONST64(0x0000000104040404), - CONST64(0x0400000000000000), CONST64(0x0400000100000000), CONST64(0x0400000004000000), CONST64(0x0400000104000000), - CONST64(0x0400000000040000), CONST64(0x0400000100040000), CONST64(0x0400000004040000), CONST64(0x0400000104040000), - CONST64(0x0400000000000400), CONST64(0x0400000100000400), CONST64(0x0400000004000400), CONST64(0x0400000104000400), - CONST64(0x0400000000040400), CONST64(0x0400000100040400), CONST64(0x0400000004040400), CONST64(0x0400000104040400), - CONST64(0x0400000000000004), CONST64(0x0400000100000004), CONST64(0x0400000004000004), CONST64(0x0400000104000004), - CONST64(0x0400000000040004), CONST64(0x0400000100040004), CONST64(0x0400000004040004), CONST64(0x0400000104040004), - CONST64(0x0400000000000404), CONST64(0x0400000100000404), CONST64(0x0400000004000404), CONST64(0x0400000104000404), - CONST64(0x0400000000040404), CONST64(0x0400000100040404), CONST64(0x0400000004040404), CONST64(0x0400000104040404), - CONST64(0x0004000000000000), CONST64(0x0004000100000000), CONST64(0x0004000004000000), CONST64(0x0004000104000000), - CONST64(0x0004000000040000), CONST64(0x0004000100040000), CONST64(0x0004000004040000), CONST64(0x0004000104040000), - CONST64(0x0004000000000400), CONST64(0x0004000100000400), CONST64(0x0004000004000400), CONST64(0x0004000104000400), - CONST64(0x0004000000040400), CONST64(0x0004000100040400), CONST64(0x0004000004040400), CONST64(0x0004000104040400), - CONST64(0x0004000000000004), CONST64(0x0004000100000004), CONST64(0x0004000004000004), CONST64(0x0004000104000004), - CONST64(0x0004000000040004), CONST64(0x0004000100040004), CONST64(0x0004000004040004), CONST64(0x0004000104040004), - CONST64(0x0004000000000404), CONST64(0x0004000100000404), CONST64(0x0004000004000404), CONST64(0x0004000104000404), - CONST64(0x0004000000040404), CONST64(0x0004000100040404), CONST64(0x0004000004040404), CONST64(0x0004000104040404), - CONST64(0x0404000000000000), CONST64(0x0404000100000000), CONST64(0x0404000004000000), CONST64(0x0404000104000000), - CONST64(0x0404000000040000), CONST64(0x0404000100040000), CONST64(0x0404000004040000), CONST64(0x0404000104040000), - CONST64(0x0404000000000400), CONST64(0x0404000100000400), CONST64(0x0404000004000400), CONST64(0x0404000104000400), - CONST64(0x0404000000040400), CONST64(0x0404000100040400), CONST64(0x0404000004040400), CONST64(0x0404000104040400), - CONST64(0x0404000000000004), CONST64(0x0404000100000004), CONST64(0x0404000004000004), CONST64(0x0404000104000004), - CONST64(0x0404000000040004), CONST64(0x0404000100040004), CONST64(0x0404000004040004), CONST64(0x0404000104040004), - CONST64(0x0404000000000404), CONST64(0x0404000100000404), CONST64(0x0404000004000404), CONST64(0x0404000104000404), - CONST64(0x0404000000040404), CONST64(0x0404000100040404), CONST64(0x0404000004040404), CONST64(0x0404000104040404), - CONST64(0x0000040000000000), CONST64(0x0000040100000000), CONST64(0x0000040004000000), CONST64(0x0000040104000000), - CONST64(0x0000040000040000), CONST64(0x0000040100040000), CONST64(0x0000040004040000), CONST64(0x0000040104040000), - CONST64(0x0000040000000400), CONST64(0x0000040100000400), CONST64(0x0000040004000400), CONST64(0x0000040104000400), - CONST64(0x0000040000040400), CONST64(0x0000040100040400), CONST64(0x0000040004040400), CONST64(0x0000040104040400), - CONST64(0x0000040000000004), CONST64(0x0000040100000004), CONST64(0x0000040004000004), CONST64(0x0000040104000004), - CONST64(0x0000040000040004), CONST64(0x0000040100040004), CONST64(0x0000040004040004), CONST64(0x0000040104040004), - CONST64(0x0000040000000404), CONST64(0x0000040100000404), CONST64(0x0000040004000404), CONST64(0x0000040104000404), - CONST64(0x0000040000040404), CONST64(0x0000040100040404), CONST64(0x0000040004040404), CONST64(0x0000040104040404), - CONST64(0x0400040000000000), CONST64(0x0400040100000000), CONST64(0x0400040004000000), CONST64(0x0400040104000000), - CONST64(0x0400040000040000), CONST64(0x0400040100040000), CONST64(0x0400040004040000), CONST64(0x0400040104040000), - CONST64(0x0400040000000400), CONST64(0x0400040100000400), CONST64(0x0400040004000400), CONST64(0x0400040104000400), - CONST64(0x0400040000040400), CONST64(0x0400040100040400), CONST64(0x0400040004040400), CONST64(0x0400040104040400), - CONST64(0x0400040000000004), CONST64(0x0400040100000004), CONST64(0x0400040004000004), CONST64(0x0400040104000004), - CONST64(0x0400040000040004), CONST64(0x0400040100040004), CONST64(0x0400040004040004), CONST64(0x0400040104040004), - CONST64(0x0400040000000404), CONST64(0x0400040100000404), CONST64(0x0400040004000404), CONST64(0x0400040104000404), - CONST64(0x0400040000040404), CONST64(0x0400040100040404), CONST64(0x0400040004040404), CONST64(0x0400040104040404), - CONST64(0x0004040000000000), CONST64(0x0004040100000000), CONST64(0x0004040004000000), CONST64(0x0004040104000000), - CONST64(0x0004040000040000), CONST64(0x0004040100040000), CONST64(0x0004040004040000), CONST64(0x0004040104040000), - CONST64(0x0004040000000400), CONST64(0x0004040100000400), CONST64(0x0004040004000400), CONST64(0x0004040104000400), - CONST64(0x0004040000040400), CONST64(0x0004040100040400), CONST64(0x0004040004040400), CONST64(0x0004040104040400), - CONST64(0x0004040000000004), CONST64(0x0004040100000004), CONST64(0x0004040004000004), CONST64(0x0004040104000004), - CONST64(0x0004040000040004), CONST64(0x0004040100040004), CONST64(0x0004040004040004), CONST64(0x0004040104040004), - CONST64(0x0004040000000404), CONST64(0x0004040100000404), CONST64(0x0004040004000404), CONST64(0x0004040104000404), - CONST64(0x0004040000040404), CONST64(0x0004040100040404), CONST64(0x0004040004040404), CONST64(0x0004040104040404), - CONST64(0x0404040000000000), CONST64(0x0404040100000000), CONST64(0x0404040004000000), CONST64(0x0404040104000000), - CONST64(0x0404040000040000), CONST64(0x0404040100040000), CONST64(0x0404040004040000), CONST64(0x0404040104040000), - CONST64(0x0404040000000400), CONST64(0x0404040100000400), CONST64(0x0404040004000400), CONST64(0x0404040104000400), - CONST64(0x0404040000040400), CONST64(0x0404040100040400), CONST64(0x0404040004040400), CONST64(0x0404040104040400), - CONST64(0x0404040000000004), CONST64(0x0404040100000004), CONST64(0x0404040004000004), CONST64(0x0404040104000004), - CONST64(0x0404040000040004), CONST64(0x0404040100040004), CONST64(0x0404040004040004), CONST64(0x0404040104040004), - CONST64(0x0404040000000404), CONST64(0x0404040100000404), CONST64(0x0404040004000404), CONST64(0x0404040104000404), - CONST64(0x0404040000040404), CONST64(0x0404040100040404), CONST64(0x0404040004040404), CONST64(0x0404040104040404) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000000400000000), CONST64(0x0000000010000000), CONST64(0x0000000410000000), - CONST64(0x0000000000100000), CONST64(0x0000000400100000), CONST64(0x0000000010100000), CONST64(0x0000000410100000), - CONST64(0x0000000000001000), CONST64(0x0000000400001000), CONST64(0x0000000010001000), CONST64(0x0000000410001000), - CONST64(0x0000000000101000), CONST64(0x0000000400101000), CONST64(0x0000000010101000), CONST64(0x0000000410101000), - CONST64(0x0000000000000010), CONST64(0x0000000400000010), CONST64(0x0000000010000010), CONST64(0x0000000410000010), - CONST64(0x0000000000100010), CONST64(0x0000000400100010), CONST64(0x0000000010100010), CONST64(0x0000000410100010), - CONST64(0x0000000000001010), CONST64(0x0000000400001010), CONST64(0x0000000010001010), CONST64(0x0000000410001010), - CONST64(0x0000000000101010), CONST64(0x0000000400101010), CONST64(0x0000000010101010), CONST64(0x0000000410101010), - CONST64(0x1000000000000000), CONST64(0x1000000400000000), CONST64(0x1000000010000000), CONST64(0x1000000410000000), - CONST64(0x1000000000100000), CONST64(0x1000000400100000), CONST64(0x1000000010100000), CONST64(0x1000000410100000), - CONST64(0x1000000000001000), CONST64(0x1000000400001000), CONST64(0x1000000010001000), CONST64(0x1000000410001000), - CONST64(0x1000000000101000), CONST64(0x1000000400101000), CONST64(0x1000000010101000), CONST64(0x1000000410101000), - CONST64(0x1000000000000010), CONST64(0x1000000400000010), CONST64(0x1000000010000010), CONST64(0x1000000410000010), - CONST64(0x1000000000100010), CONST64(0x1000000400100010), CONST64(0x1000000010100010), CONST64(0x1000000410100010), - CONST64(0x1000000000001010), CONST64(0x1000000400001010), CONST64(0x1000000010001010), CONST64(0x1000000410001010), - CONST64(0x1000000000101010), CONST64(0x1000000400101010), CONST64(0x1000000010101010), CONST64(0x1000000410101010), - CONST64(0x0010000000000000), CONST64(0x0010000400000000), CONST64(0x0010000010000000), CONST64(0x0010000410000000), - CONST64(0x0010000000100000), CONST64(0x0010000400100000), CONST64(0x0010000010100000), CONST64(0x0010000410100000), - CONST64(0x0010000000001000), CONST64(0x0010000400001000), CONST64(0x0010000010001000), CONST64(0x0010000410001000), - CONST64(0x0010000000101000), CONST64(0x0010000400101000), CONST64(0x0010000010101000), CONST64(0x0010000410101000), - CONST64(0x0010000000000010), CONST64(0x0010000400000010), CONST64(0x0010000010000010), CONST64(0x0010000410000010), - CONST64(0x0010000000100010), CONST64(0x0010000400100010), CONST64(0x0010000010100010), CONST64(0x0010000410100010), - CONST64(0x0010000000001010), CONST64(0x0010000400001010), CONST64(0x0010000010001010), CONST64(0x0010000410001010), - CONST64(0x0010000000101010), CONST64(0x0010000400101010), CONST64(0x0010000010101010), CONST64(0x0010000410101010), - CONST64(0x1010000000000000), CONST64(0x1010000400000000), CONST64(0x1010000010000000), CONST64(0x1010000410000000), - CONST64(0x1010000000100000), CONST64(0x1010000400100000), CONST64(0x1010000010100000), CONST64(0x1010000410100000), - CONST64(0x1010000000001000), CONST64(0x1010000400001000), CONST64(0x1010000010001000), CONST64(0x1010000410001000), - CONST64(0x1010000000101000), CONST64(0x1010000400101000), CONST64(0x1010000010101000), CONST64(0x1010000410101000), - CONST64(0x1010000000000010), CONST64(0x1010000400000010), CONST64(0x1010000010000010), CONST64(0x1010000410000010), - CONST64(0x1010000000100010), CONST64(0x1010000400100010), CONST64(0x1010000010100010), CONST64(0x1010000410100010), - CONST64(0x1010000000001010), CONST64(0x1010000400001010), CONST64(0x1010000010001010), CONST64(0x1010000410001010), - CONST64(0x1010000000101010), CONST64(0x1010000400101010), CONST64(0x1010000010101010), CONST64(0x1010000410101010), - CONST64(0x0000100000000000), CONST64(0x0000100400000000), CONST64(0x0000100010000000), CONST64(0x0000100410000000), - CONST64(0x0000100000100000), CONST64(0x0000100400100000), CONST64(0x0000100010100000), CONST64(0x0000100410100000), - CONST64(0x0000100000001000), CONST64(0x0000100400001000), CONST64(0x0000100010001000), CONST64(0x0000100410001000), - CONST64(0x0000100000101000), CONST64(0x0000100400101000), CONST64(0x0000100010101000), CONST64(0x0000100410101000), - CONST64(0x0000100000000010), CONST64(0x0000100400000010), CONST64(0x0000100010000010), CONST64(0x0000100410000010), - CONST64(0x0000100000100010), CONST64(0x0000100400100010), CONST64(0x0000100010100010), CONST64(0x0000100410100010), - CONST64(0x0000100000001010), CONST64(0x0000100400001010), CONST64(0x0000100010001010), CONST64(0x0000100410001010), - CONST64(0x0000100000101010), CONST64(0x0000100400101010), CONST64(0x0000100010101010), CONST64(0x0000100410101010), - CONST64(0x1000100000000000), CONST64(0x1000100400000000), CONST64(0x1000100010000000), CONST64(0x1000100410000000), - CONST64(0x1000100000100000), CONST64(0x1000100400100000), CONST64(0x1000100010100000), CONST64(0x1000100410100000), - CONST64(0x1000100000001000), CONST64(0x1000100400001000), CONST64(0x1000100010001000), CONST64(0x1000100410001000), - CONST64(0x1000100000101000), CONST64(0x1000100400101000), CONST64(0x1000100010101000), CONST64(0x1000100410101000), - CONST64(0x1000100000000010), CONST64(0x1000100400000010), CONST64(0x1000100010000010), CONST64(0x1000100410000010), - CONST64(0x1000100000100010), CONST64(0x1000100400100010), CONST64(0x1000100010100010), CONST64(0x1000100410100010), - CONST64(0x1000100000001010), CONST64(0x1000100400001010), CONST64(0x1000100010001010), CONST64(0x1000100410001010), - CONST64(0x1000100000101010), CONST64(0x1000100400101010), CONST64(0x1000100010101010), CONST64(0x1000100410101010), - CONST64(0x0010100000000000), CONST64(0x0010100400000000), CONST64(0x0010100010000000), CONST64(0x0010100410000000), - CONST64(0x0010100000100000), CONST64(0x0010100400100000), CONST64(0x0010100010100000), CONST64(0x0010100410100000), - CONST64(0x0010100000001000), CONST64(0x0010100400001000), CONST64(0x0010100010001000), CONST64(0x0010100410001000), - CONST64(0x0010100000101000), CONST64(0x0010100400101000), CONST64(0x0010100010101000), CONST64(0x0010100410101000), - CONST64(0x0010100000000010), CONST64(0x0010100400000010), CONST64(0x0010100010000010), CONST64(0x0010100410000010), - CONST64(0x0010100000100010), CONST64(0x0010100400100010), CONST64(0x0010100010100010), CONST64(0x0010100410100010), - CONST64(0x0010100000001010), CONST64(0x0010100400001010), CONST64(0x0010100010001010), CONST64(0x0010100410001010), - CONST64(0x0010100000101010), CONST64(0x0010100400101010), CONST64(0x0010100010101010), CONST64(0x0010100410101010), - CONST64(0x1010100000000000), CONST64(0x1010100400000000), CONST64(0x1010100010000000), CONST64(0x1010100410000000), - CONST64(0x1010100000100000), CONST64(0x1010100400100000), CONST64(0x1010100010100000), CONST64(0x1010100410100000), - CONST64(0x1010100000001000), CONST64(0x1010100400001000), CONST64(0x1010100010001000), CONST64(0x1010100410001000), - CONST64(0x1010100000101000), CONST64(0x1010100400101000), CONST64(0x1010100010101000), CONST64(0x1010100410101000), - CONST64(0x1010100000000010), CONST64(0x1010100400000010), CONST64(0x1010100010000010), CONST64(0x1010100410000010), - CONST64(0x1010100000100010), CONST64(0x1010100400100010), CONST64(0x1010100010100010), CONST64(0x1010100410100010), - CONST64(0x1010100000001010), CONST64(0x1010100400001010), CONST64(0x1010100010001010), CONST64(0x1010100410001010), - CONST64(0x1010100000101010), CONST64(0x1010100400101010), CONST64(0x1010100010101010), CONST64(0x1010100410101010) - }, -{ CONST64(0x0000000000000000), CONST64(0x0000001000000000), CONST64(0x0000000040000000), CONST64(0x0000001040000000), - CONST64(0x0000000000400000), CONST64(0x0000001000400000), CONST64(0x0000000040400000), CONST64(0x0000001040400000), - CONST64(0x0000000000004000), CONST64(0x0000001000004000), CONST64(0x0000000040004000), CONST64(0x0000001040004000), - CONST64(0x0000000000404000), CONST64(0x0000001000404000), CONST64(0x0000000040404000), CONST64(0x0000001040404000), - CONST64(0x0000000000000040), CONST64(0x0000001000000040), CONST64(0x0000000040000040), CONST64(0x0000001040000040), - CONST64(0x0000000000400040), CONST64(0x0000001000400040), CONST64(0x0000000040400040), CONST64(0x0000001040400040), - CONST64(0x0000000000004040), CONST64(0x0000001000004040), CONST64(0x0000000040004040), CONST64(0x0000001040004040), - CONST64(0x0000000000404040), CONST64(0x0000001000404040), CONST64(0x0000000040404040), CONST64(0x0000001040404040), - CONST64(0x4000000000000000), CONST64(0x4000001000000000), CONST64(0x4000000040000000), CONST64(0x4000001040000000), - CONST64(0x4000000000400000), CONST64(0x4000001000400000), CONST64(0x4000000040400000), CONST64(0x4000001040400000), - CONST64(0x4000000000004000), CONST64(0x4000001000004000), CONST64(0x4000000040004000), CONST64(0x4000001040004000), - CONST64(0x4000000000404000), CONST64(0x4000001000404000), CONST64(0x4000000040404000), CONST64(0x4000001040404000), - CONST64(0x4000000000000040), CONST64(0x4000001000000040), CONST64(0x4000000040000040), CONST64(0x4000001040000040), - CONST64(0x4000000000400040), CONST64(0x4000001000400040), CONST64(0x4000000040400040), CONST64(0x4000001040400040), - CONST64(0x4000000000004040), CONST64(0x4000001000004040), CONST64(0x4000000040004040), CONST64(0x4000001040004040), - CONST64(0x4000000000404040), CONST64(0x4000001000404040), CONST64(0x4000000040404040), CONST64(0x4000001040404040), - CONST64(0x0040000000000000), CONST64(0x0040001000000000), CONST64(0x0040000040000000), CONST64(0x0040001040000000), - CONST64(0x0040000000400000), CONST64(0x0040001000400000), CONST64(0x0040000040400000), CONST64(0x0040001040400000), - CONST64(0x0040000000004000), CONST64(0x0040001000004000), CONST64(0x0040000040004000), CONST64(0x0040001040004000), - CONST64(0x0040000000404000), CONST64(0x0040001000404000), CONST64(0x0040000040404000), CONST64(0x0040001040404000), - CONST64(0x0040000000000040), CONST64(0x0040001000000040), CONST64(0x0040000040000040), CONST64(0x0040001040000040), - CONST64(0x0040000000400040), CONST64(0x0040001000400040), CONST64(0x0040000040400040), CONST64(0x0040001040400040), - CONST64(0x0040000000004040), CONST64(0x0040001000004040), CONST64(0x0040000040004040), CONST64(0x0040001040004040), - CONST64(0x0040000000404040), CONST64(0x0040001000404040), CONST64(0x0040000040404040), CONST64(0x0040001040404040), - CONST64(0x4040000000000000), CONST64(0x4040001000000000), CONST64(0x4040000040000000), CONST64(0x4040001040000000), - CONST64(0x4040000000400000), CONST64(0x4040001000400000), CONST64(0x4040000040400000), CONST64(0x4040001040400000), - CONST64(0x4040000000004000), CONST64(0x4040001000004000), CONST64(0x4040000040004000), CONST64(0x4040001040004000), - CONST64(0x4040000000404000), CONST64(0x4040001000404000), CONST64(0x4040000040404000), CONST64(0x4040001040404000), - CONST64(0x4040000000000040), CONST64(0x4040001000000040), CONST64(0x4040000040000040), CONST64(0x4040001040000040), - CONST64(0x4040000000400040), CONST64(0x4040001000400040), CONST64(0x4040000040400040), CONST64(0x4040001040400040), - CONST64(0x4040000000004040), CONST64(0x4040001000004040), CONST64(0x4040000040004040), CONST64(0x4040001040004040), - CONST64(0x4040000000404040), CONST64(0x4040001000404040), CONST64(0x4040000040404040), CONST64(0x4040001040404040), - CONST64(0x0000400000000000), CONST64(0x0000401000000000), CONST64(0x0000400040000000), CONST64(0x0000401040000000), - CONST64(0x0000400000400000), CONST64(0x0000401000400000), CONST64(0x0000400040400000), CONST64(0x0000401040400000), - CONST64(0x0000400000004000), CONST64(0x0000401000004000), CONST64(0x0000400040004000), CONST64(0x0000401040004000), - CONST64(0x0000400000404000), CONST64(0x0000401000404000), CONST64(0x0000400040404000), CONST64(0x0000401040404000), - CONST64(0x0000400000000040), CONST64(0x0000401000000040), CONST64(0x0000400040000040), CONST64(0x0000401040000040), - CONST64(0x0000400000400040), CONST64(0x0000401000400040), CONST64(0x0000400040400040), CONST64(0x0000401040400040), - CONST64(0x0000400000004040), CONST64(0x0000401000004040), CONST64(0x0000400040004040), CONST64(0x0000401040004040), - CONST64(0x0000400000404040), CONST64(0x0000401000404040), CONST64(0x0000400040404040), CONST64(0x0000401040404040), - CONST64(0x4000400000000000), CONST64(0x4000401000000000), CONST64(0x4000400040000000), CONST64(0x4000401040000000), - CONST64(0x4000400000400000), CONST64(0x4000401000400000), CONST64(0x4000400040400000), CONST64(0x4000401040400000), - CONST64(0x4000400000004000), CONST64(0x4000401000004000), CONST64(0x4000400040004000), CONST64(0x4000401040004000), - CONST64(0x4000400000404000), CONST64(0x4000401000404000), CONST64(0x4000400040404000), CONST64(0x4000401040404000), - CONST64(0x4000400000000040), CONST64(0x4000401000000040), CONST64(0x4000400040000040), CONST64(0x4000401040000040), - CONST64(0x4000400000400040), CONST64(0x4000401000400040), CONST64(0x4000400040400040), CONST64(0x4000401040400040), - CONST64(0x4000400000004040), CONST64(0x4000401000004040), CONST64(0x4000400040004040), CONST64(0x4000401040004040), - CONST64(0x4000400000404040), CONST64(0x4000401000404040), CONST64(0x4000400040404040), CONST64(0x4000401040404040), - CONST64(0x0040400000000000), CONST64(0x0040401000000000), CONST64(0x0040400040000000), CONST64(0x0040401040000000), - CONST64(0x0040400000400000), CONST64(0x0040401000400000), CONST64(0x0040400040400000), CONST64(0x0040401040400000), - CONST64(0x0040400000004000), CONST64(0x0040401000004000), CONST64(0x0040400040004000), CONST64(0x0040401040004000), - CONST64(0x0040400000404000), CONST64(0x0040401000404000), CONST64(0x0040400040404000), CONST64(0x0040401040404000), - CONST64(0x0040400000000040), CONST64(0x0040401000000040), CONST64(0x0040400040000040), CONST64(0x0040401040000040), - CONST64(0x0040400000400040), CONST64(0x0040401000400040), CONST64(0x0040400040400040), CONST64(0x0040401040400040), - CONST64(0x0040400000004040), CONST64(0x0040401000004040), CONST64(0x0040400040004040), CONST64(0x0040401040004040), - CONST64(0x0040400000404040), CONST64(0x0040401000404040), CONST64(0x0040400040404040), CONST64(0x0040401040404040), - CONST64(0x4040400000000000), CONST64(0x4040401000000000), CONST64(0x4040400040000000), CONST64(0x4040401040000000), - CONST64(0x4040400000400000), CONST64(0x4040401000400000), CONST64(0x4040400040400000), CONST64(0x4040401040400000), - CONST64(0x4040400000004000), CONST64(0x4040401000004000), CONST64(0x4040400040004000), CONST64(0x4040401040004000), - CONST64(0x4040400000404000), CONST64(0x4040401000404000), CONST64(0x4040400040404000), CONST64(0x4040401040404000), - CONST64(0x4040400000000040), CONST64(0x4040401000000040), CONST64(0x4040400040000040), CONST64(0x4040401040000040), - CONST64(0x4040400000400040), CONST64(0x4040401000400040), CONST64(0x4040400040400040), CONST64(0x4040401040400040), - CONST64(0x4040400000004040), CONST64(0x4040401000004040), CONST64(0x4040400040004040), CONST64(0x4040401040004040), - CONST64(0x4040400000404040), CONST64(0x4040401000404040), CONST64(0x4040400040404040), CONST64(0x4040401040404040) - }}; - -#endif - - -static void cookey(const ulong32 *raw1, ulong32 *keyout); - -#ifdef LTC_CLEAN_STACK -static void _deskey(const unsigned char *key, short edf, ulong32 *keyout) -#else -static void deskey(const unsigned char *key, short edf, ulong32 *keyout) -#endif -{ - ulong32 i, j, l, m, n, kn[32]; - unsigned char pc1m[56], pcr[56]; - - for (j=0; j < 56; j++) { - l = (ulong32)pc1[j]; - m = l & 7; - pc1m[j] = (unsigned char)((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0); - } - - for (i=0; i < 16; i++) { - if (edf == DE1) { - m = (15 - i) << 1; - } else { - m = i << 1; - } - n = m + 1; - kn[m] = kn[n] = 0L; - for (j=0; j < 28; j++) { - l = j + (ulong32)totrot[i]; - if (l < 28) { - pcr[j] = pc1m[l]; - } else { - pcr[j] = pc1m[l - 28]; - } - } - for (/*j = 28*/; j < 56; j++) { - l = j + (ulong32)totrot[i]; - if (l < 56) { - pcr[j] = pc1m[l]; - } else { - pcr[j] = pc1m[l - 28]; - } - } - for (j=0; j < 24; j++) { - if ((int)pcr[(int)pc2[j]] != 0) { - kn[m] |= bigbyte[j]; - } - if ((int)pcr[(int)pc2[j+24]] != 0) { - kn[n] |= bigbyte[j]; - } - } - } - - cookey(kn, keyout); -} - -#ifdef LTC_CLEAN_STACK -static void deskey(const unsigned char *key, short edf, ulong32 *keyout) -{ - _deskey(key, edf, keyout); - burn_stack(sizeof(int)*5 + sizeof(ulong32)*32 + sizeof(unsigned char)*112); -} -#endif - -#ifdef LTC_CLEAN_STACK -static void _cookey(const ulong32 *raw1, ulong32 *keyout) -#else -static void cookey(const ulong32 *raw1, ulong32 *keyout) -#endif -{ - ulong32 *cook; - const ulong32 *raw0; - ulong32 dough[32]; - int i; - - cook = dough; - for(i=0; i < 16; i++, raw1++) - { - raw0 = raw1++; - *cook = (*raw0 & 0x00fc0000L) << 6; - *cook |= (*raw0 & 0x00000fc0L) << 10; - *cook |= (*raw1 & 0x00fc0000L) >> 10; - *cook++ |= (*raw1 & 0x00000fc0L) >> 6; - *cook = (*raw0 & 0x0003f000L) << 12; - *cook |= (*raw0 & 0x0000003fL) << 16; - *cook |= (*raw1 & 0x0003f000L) >> 4; - *cook++ |= (*raw1 & 0x0000003fL); - } - - XMEMCPY(keyout, dough, sizeof dough); -} - -#ifdef LTC_CLEAN_STACK -static void cookey(const ulong32 *raw1, ulong32 *keyout) -{ - _cookey(raw1, keyout); - burn_stack(sizeof(ulong32 *) * 2 + sizeof(ulong32)*32 + sizeof(int)); -} -#endif - -#ifndef LTC_CLEAN_STACK -static void desfunc(ulong32 *block, const ulong32 *keys) -#else -static void _desfunc(ulong32 *block, const ulong32 *keys) -#endif -{ - ulong32 work, right, leftt; - int cur_round; - - leftt = block[0]; - right = block[1]; - -#ifdef LTC_SMALL_CODE - work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL; - right ^= work; - leftt ^= (work << 4); - - work = ((leftt >> 16) ^ right) & 0x0000ffffL; - right ^= work; - leftt ^= (work << 16); - - work = ((right >> 2) ^ leftt) & 0x33333333L; - leftt ^= work; - right ^= (work << 2); - - work = ((right >> 8) ^ leftt) & 0x00ff00ffL; - leftt ^= work; - right ^= (work << 8); - - right = ROLc(right, 1); - work = (leftt ^ right) & 0xaaaaaaaaL; - - leftt ^= work; - right ^= work; - leftt = ROLc(leftt, 1); -#else - { - ulong64 tmp; - tmp = des_ip[0][byte(leftt, 0)] ^ - des_ip[1][byte(leftt, 1)] ^ - des_ip[2][byte(leftt, 2)] ^ - des_ip[3][byte(leftt, 3)] ^ - des_ip[4][byte(right, 0)] ^ - des_ip[5][byte(right, 1)] ^ - des_ip[6][byte(right, 2)] ^ - des_ip[7][byte(right, 3)]; - leftt = (ulong32)(tmp >> 32); - right = (ulong32)(tmp & 0xFFFFFFFFUL); - } -#endif - - for (cur_round = 0; cur_round < 8; cur_round++) { - work = RORc(right, 4) ^ *keys++; - leftt ^= SP7[work & 0x3fL] - ^ SP5[(work >> 8) & 0x3fL] - ^ SP3[(work >> 16) & 0x3fL] - ^ SP1[(work >> 24) & 0x3fL]; - work = right ^ *keys++; - leftt ^= SP8[ work & 0x3fL] - ^ SP6[(work >> 8) & 0x3fL] - ^ SP4[(work >> 16) & 0x3fL] - ^ SP2[(work >> 24) & 0x3fL]; - - work = RORc(leftt, 4) ^ *keys++; - right ^= SP7[ work & 0x3fL] - ^ SP5[(work >> 8) & 0x3fL] - ^ SP3[(work >> 16) & 0x3fL] - ^ SP1[(work >> 24) & 0x3fL]; - work = leftt ^ *keys++; - right ^= SP8[ work & 0x3fL] - ^ SP6[(work >> 8) & 0x3fL] - ^ SP4[(work >> 16) & 0x3fL] - ^ SP2[(work >> 24) & 0x3fL]; - } - -#ifdef LTC_SMALL_CODE - right = RORc(right, 1); - work = (leftt ^ right) & 0xaaaaaaaaL; - leftt ^= work; - right ^= work; - leftt = RORc(leftt, 1); - work = ((leftt >> 8) ^ right) & 0x00ff00ffL; - right ^= work; - leftt ^= (work << 8); - /* -- */ - work = ((leftt >> 2) ^ right) & 0x33333333L; - right ^= work; - leftt ^= (work << 2); - work = ((right >> 16) ^ leftt) & 0x0000ffffL; - leftt ^= work; - right ^= (work << 16); - work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL; - leftt ^= work; - right ^= (work << 4); -#else - { - ulong64 tmp; - tmp = des_fp[0][byte(leftt, 0)] ^ - des_fp[1][byte(leftt, 1)] ^ - des_fp[2][byte(leftt, 2)] ^ - des_fp[3][byte(leftt, 3)] ^ - des_fp[4][byte(right, 0)] ^ - des_fp[5][byte(right, 1)] ^ - des_fp[6][byte(right, 2)] ^ - des_fp[7][byte(right, 3)]; - leftt = (ulong32)(tmp >> 32); - right = (ulong32)(tmp & 0xFFFFFFFFUL); - } -#endif - - block[0] = right; - block[1] = leftt; -} - -#ifdef LTC_CLEAN_STACK -static void desfunc(ulong32 *block, const ulong32 *keys) -{ - _desfunc(block, keys); - burn_stack(sizeof(ulong32) * 4 + sizeof(int)); -} -#endif - - /** - Initialize the LTC_DES block cipher - @param key The symmetric key you wish to pass - @param keylen The key length in bytes - @param num_rounds The number of rounds desired (0 for default) - @param skey The key in as scheduled by this function. - @return CRYPT_OK if successful - */ -int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) -{ - LTC_ARGCHK(key != NULL); - LTC_ARGCHK(skey != NULL); - - if (num_rounds != 0 && num_rounds != 16) { - return CRYPT_INVALID_ROUNDS; - } - - if (keylen != 8) { - return CRYPT_INVALID_KEYSIZE; - } - - deskey(key, EN0, skey->des.ek); - deskey(key, DE1, skey->des.dk); - - return CRYPT_OK; -} - -#ifdef LTC_DES3 - /** - Initialize the 3LTC_DES-EDE block cipher - @param key The symmetric key you wish to pass - @param keylen The key length in bytes - @param num_rounds The number of rounds desired (0 for default) - @param skey The key in as scheduled by this function. - @return CRYPT_OK if successful - */ -int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) -{ - LTC_ARGCHK(key != NULL); - LTC_ARGCHK(skey != NULL); - - if(num_rounds != 0 && num_rounds != 16) { - return CRYPT_INVALID_ROUNDS; - } - - if (keylen != 24) { - return CRYPT_INVALID_KEYSIZE; - } - - deskey(key, EN0, skey->des3.ek[0]); - deskey(key+8, DE1, skey->des3.ek[1]); - deskey(key+16, EN0, skey->des3.ek[2]); - - deskey(key, DE1, skey->des3.dk[2]); - deskey(key+8, EN0, skey->des3.dk[1]); - deskey(key+16, DE1, skey->des3.dk[0]); - - return CRYPT_OK; -} -#endif - -/** - Encrypts a block of text with LTC_DES - @param pt The input plaintext (8 bytes) - @param ct The output ciphertext (8 bytes) - @param skey The key as scheduled - @return CRYPT_OK if successful -*/ -int des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) -{ - ulong32 work[2]; - LTC_ARGCHK(pt != NULL); - LTC_ARGCHK(ct != NULL); - LTC_ARGCHK(skey != NULL); - LOAD32H(work[0], pt+0); - LOAD32H(work[1], pt+4); - desfunc(work, skey->des.ek); - STORE32H(work[0],ct+0); - STORE32H(work[1],ct+4); - return CRYPT_OK; -} - -/** - Decrypts a block of text with LTC_DES - @param ct The input ciphertext (8 bytes) - @param pt The output plaintext (8 bytes) - @param skey The key as scheduled - @return CRYPT_OK if successful -*/ -int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) -{ - ulong32 work[2]; - LTC_ARGCHK(pt != NULL); - LTC_ARGCHK(ct != NULL); - LTC_ARGCHK(skey != NULL); - LOAD32H(work[0], ct+0); - LOAD32H(work[1], ct+4); - desfunc(work, skey->des.dk); - STORE32H(work[0],pt+0); - STORE32H(work[1],pt+4); - return CRYPT_OK; -} - -#ifdef LTC_DES3 -/** - Encrypts a block of text with 3LTC_DES-EDE - @param pt The input plaintext (8 bytes) - @param ct The output ciphertext (8 bytes) - @param skey The key as scheduled - @return CRYPT_OK if successful -*/ -int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) -{ - ulong32 work[2]; - - LTC_ARGCHK(pt != NULL); - LTC_ARGCHK(ct != NULL); - LTC_ARGCHK(skey != NULL); - LOAD32H(work[0], pt+0); - LOAD32H(work[1], pt+4); - desfunc(work, skey->des3.ek[0]); - desfunc(work, skey->des3.ek[1]); - desfunc(work, skey->des3.ek[2]); - STORE32H(work[0],ct+0); - STORE32H(work[1],ct+4); - return CRYPT_OK; -} - -/** - Decrypts a block of text with 3LTC_DES-EDE - @param ct The input ciphertext (8 bytes) - @param pt The output plaintext (8 bytes) - @param skey The key as scheduled - @return CRYPT_OK if successful -*/ -int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) -{ - ulong32 work[2]; - LTC_ARGCHK(pt != NULL); - LTC_ARGCHK(ct != NULL); - LTC_ARGCHK(skey != NULL); - LOAD32H(work[0], ct+0); - LOAD32H(work[1], ct+4); - desfunc(work, skey->des3.dk[0]); - desfunc(work, skey->des3.dk[1]); - desfunc(work, skey->des3.dk[2]); - STORE32H(work[0],pt+0); - STORE32H(work[1],pt+4); - return CRYPT_OK; -} -#endif - -/** - Performs a self-test of the LTC_DES block cipher - @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled -*/ -int des_test(void) -{ - #ifndef LTC_TEST - return CRYPT_NOP; - #else - int err; - static const struct des_test_case { - int num, mode; /* mode 1 = encrypt */ - unsigned char key[8], txt[8], out[8]; - } cases[] = { - { 1, 1, { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 } }, - { 2, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 }, - { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 3, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 }, - { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 4, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA }, - { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 5, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F }, - { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 6, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 }, - { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 7, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF }, - { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 8, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F }, - { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 9, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 }, - { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - {10, 1, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A }, - { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - - { 1, 0, { 0x10, 0x31, 0x6E, 0x02, 0x8C, 0x8F, 0x3B, 0x4A }, - { 0x82, 0xDC, 0xBA, 0xFB, 0xDE, 0xAB, 0x66, 0x02 }, - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, - { 2, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x95, 0xF8, 0xA5, 0xE5, 0xDD, 0x31, 0xD9, 0x00 } }, - { 3, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0xDD, 0x7F, 0x12, 0x1C, 0xA5, 0x01, 0x56, 0x19 } }, - { 4, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x2E, 0x86, 0x53, 0x10, 0x4F, 0x38, 0x34, 0xEA } }, - { 5, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x4B, 0xD3, 0x88, 0xFF, 0x6C, 0xD8, 0x1D, 0x4F } }, - { 6, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x20, 0xB9, 0xE7, 0x67, 0xB2, 0xFB, 0x14, 0x56 } }, - { 7, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x55, 0x57, 0x93, 0x80, 0xD7, 0x71, 0x38, 0xEF } }, - { 8, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x6C, 0xC5, 0xDE, 0xFA, 0xAF, 0x04, 0x51, 0x2F } }, - { 9, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0x0D, 0x9F, 0x27, 0x9B, 0xA5, 0xD8, 0x72, 0x60 } }, - {10, 0, { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, - { 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, - { 0xD9, 0x03, 0x1B, 0x02, 0x71, 0xBD, 0x5A, 0x0A } } - - /*** more test cases you could add if you are not convinced (the above test cases aren't really too good): - - key plaintext ciphertext - 0000000000000000 0000000000000000 8CA64DE9C1B123A7 - FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58 - 3000000000000000 1000000000000001 958E6E627A05557B - 1111111111111111 1111111111111111 F40379AB9E0EC533 - 0123456789ABCDEF 1111111111111111 17668DFC7292532D - 1111111111111111 0123456789ABCDEF 8A5AE1F81AB8F2DD - 0000000000000000 0000000000000000 8CA64DE9C1B123A7 - FEDCBA9876543210 0123456789ABCDEF ED39D950FA74BCC4 - 7CA110454A1A6E57 01A1D6D039776742 690F5B0D9A26939B - 0131D9619DC1376E 5CD54CA83DEF57DA 7A389D10354BD271 - 07A1133E4A0B2686 0248D43806F67172 868EBB51CAB4599A - 3849674C2602319E 51454B582DDF440A 7178876E01F19B2A - 04B915BA43FEB5B6 42FD443059577FA2 AF37FB421F8C4095 - 0113B970FD34F2CE 059B5E0851CF143A 86A560F10EC6D85B - 0170F175468FB5E6 0756D8E0774761D2 0CD3DA020021DC09 - 43297FAD38E373FE 762514B829BF486A EA676B2CB7DB2B7A - 07A7137045DA2A16 3BDD119049372802 DFD64A815CAF1A0F - 04689104C2FD3B2F 26955F6835AF609A 5C513C9C4886C088 - 37D06BB516CB7546 164D5E404F275232 0A2AEEAE3FF4AB77 - 1F08260D1AC2465E 6B056E18759F5CCA EF1BF03E5DFA575A - 584023641ABA6176 004BD6EF09176062 88BF0DB6D70DEE56 - 025816164629B007 480D39006EE762F2 A1F9915541020B56 - 49793EBC79B3258F 437540C8698F3CFA 6FBF1CAFCFFD0556 - 4FB05E1515AB73A7 072D43A077075292 2F22E49BAB7CA1AC - 49E95D6D4CA229BF 02FE55778117F12A 5A6B612CC26CCE4A - 018310DC409B26D6 1D9D5C5018F728C2 5F4C038ED12B2E41 - 1C587F1C13924FEF 305532286D6F295A 63FAC0D034D9F793 - 0101010101010101 0123456789ABCDEF 617B3A0CE8F07100 - 1F1F1F1F0E0E0E0E 0123456789ABCDEF DB958605F8C8C606 - E0FEE0FEF1FEF1FE 0123456789ABCDEF EDBFD1C66C29CCC7 - 0000000000000000 FFFFFFFFFFFFFFFF 355550B2150E2451 - FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE - 0123456789ABCDEF 0000000000000000 D5D44FF720683D0D - FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2 - - http://www.ecs.soton.ac.uk/~prw99r/ez438/vectors.txt - ***/ - }; - int i, y; - unsigned char tmp[8]; - symmetric_key des; - - for(i=0; i < (int)(sizeof(cases)/sizeof(cases[0])); i++) - { - if ((err = des_setup(cases[i].key, 8, 0, &des)) != CRYPT_OK) { - return err; - } - if (cases[i].mode != 0) { - des_ecb_encrypt(cases[i].txt, tmp, &des); - } else { - des_ecb_decrypt(cases[i].txt, tmp, &des); - } - - if (XMEMCMP(cases[i].out, tmp, sizeof(tmp)) != 0) { - return CRYPT_FAIL_TESTVECTOR; - } - - /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ - for (y = 0; y < 8; y++) tmp[y] = 0; - for (y = 0; y < 1000; y++) des_ecb_encrypt(tmp, tmp, &des); - for (y = 0; y < 1000; y++) des_ecb_decrypt(tmp, tmp, &des); - for (y = 0; y < 8; y++) if (tmp[y] != 0) return CRYPT_FAIL_TESTVECTOR; -} - - return CRYPT_OK; - #endif -} - -#ifdef LTC_DES3 -int des3_test(void) -{ - #ifndef LTC_TEST - return CRYPT_NOP; - #else - unsigned char key[24], pt[8], ct[8], tmp[8]; - symmetric_key skey; - int x, err; - - if ((err = des_test()) != CRYPT_OK) { - return err; - } - - for (x = 0; x < 8; x++) { - pt[x] = x; - } - - for (x = 0; x < 24; x++) { - key[x] = x; - } - - if ((err = des3_setup(key, 24, 0, &skey)) != CRYPT_OK) { - return err; - } - - des3_ecb_encrypt(pt, ct, &skey); - des3_ecb_decrypt(ct, tmp, &skey); - - if (XMEMCMP(pt, tmp, 8) != 0) { - return CRYPT_FAIL_TESTVECTOR; - } - - return CRYPT_OK; - #endif -} -#endif - -/** Terminate the context - @param skey The scheduled key -*/ -void des_done(symmetric_key *skey) -{ -} - -#ifdef LTC_DES3 -/** Terminate the context - @param skey The scheduled key -*/ -void des3_done(symmetric_key *skey) -{ -} -#endif - - -/** - Gets suitable key size - @param keysize [in/out] The length of the recommended key (in bytes). This function will store the suitable size back in this variable. - @return CRYPT_OK if the input key size is acceptable. -*/ -int des_keysize(int *keysize) -{ - LTC_ARGCHK(keysize != NULL); - if(*keysize < 8) { - return CRYPT_INVALID_KEYSIZE; - } - *keysize = 8; - return CRYPT_OK; -} - -#ifdef LTC_DES3 -/** - Gets suitable key size - @param keysize [in/out] The length of the recommended key (in bytes). This function will store the suitable size back in this variable. - @return CRYPT_OK if the input key size is acceptable. -*/ -int des3_keysize(int *keysize) -{ - LTC_ARGCHK(keysize != NULL); - if(*keysize < 24) { - return CRYPT_INVALID_KEYSIZE; - } - *keysize = 24; - return CRYPT_OK; -} -#endif - -#endif - - -/* $Source: /cvs/libtom/libtomcrypt/src/ciphers/des.c,v $ */ -/* $Revision: 1.15 $ */ -/* $Date: 2007/05/12 14:20:27 $ */ diff --git a/crypto/md4.c b/crypto/md4.c deleted file mode 100644 index a030d301..00000000 --- a/crypto/md4.c +++ /dev/null @@ -1,307 +0,0 @@ -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org - */ -#include "tomcrypt.h" - -/** - @param md4.c - Submitted by Dobes Vandermeer (dobes@smartt.com) -*/ - -#ifdef LTC_MD4 - -const struct ltc_hash_descriptor md4_desc = -{ - "md4", - 6, - 16, - 64, - - /* OID */ - { 1, 2, 840, 113549, 2, 4, }, - 6, - - &md4_init, - &md4_process, - &md4_done, - &md4_test, - NULL -}; - -#define S11 3 -#define S12 7 -#define S13 11 -#define S14 19 -#define S21 3 -#define S22 5 -#define S23 9 -#define S24 13 -#define S31 3 -#define S32 9 -#define S33 11 -#define S34 15 - -/* F, G and H are basic LTC_MD4 functions. */ -#define F(x, y, z) (z ^ (x & (y ^ z))) -#define G(x, y, z) ((x & y) | (z & (x | y))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) - -/* ROTATE_LEFT rotates x left n bits. */ -#define ROTATE_LEFT(x, n) ROLc(x, n) - -/* FF, GG and HH are transformations for rounds 1, 2 and 3 */ -/* Rotation is separate from addition to prevent recomputation */ - -#define FF(a, b, c, d, x, s) { \ - (a) += F ((b), (c), (d)) + (x); \ - (a) = ROTATE_LEFT ((a), (s)); \ - } -#define GG(a, b, c, d, x, s) { \ - (a) += G ((b), (c), (d)) + (x) + 0x5a827999UL; \ - (a) = ROTATE_LEFT ((a), (s)); \ - } -#define HH(a, b, c, d, x, s) { \ - (a) += H ((b), (c), (d)) + (x) + 0x6ed9eba1UL; \ - (a) = ROTATE_LEFT ((a), (s)); \ - } - -#ifdef LTC_CLEAN_STACK -static int _md4_compress(hash_state *md, unsigned char *buf) -#else -static int md4_compress(hash_state *md, unsigned char *buf) -#endif -{ - ulong32 x[16], a, b, c, d; - int i; - - /* copy state */ - a = md->md4.state[0]; - b = md->md4.state[1]; - c = md->md4.state[2]; - d = md->md4.state[3]; - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) { - LOAD32L(x[i], buf + (4*i)); - } - - /* Round 1 */ - FF (a, b, c, d, x[ 0], S11); /* 1 */ - FF (d, a, b, c, x[ 1], S12); /* 2 */ - FF (c, d, a, b, x[ 2], S13); /* 3 */ - FF (b, c, d, a, x[ 3], S14); /* 4 */ - FF (a, b, c, d, x[ 4], S11); /* 5 */ - FF (d, a, b, c, x[ 5], S12); /* 6 */ - FF (c, d, a, b, x[ 6], S13); /* 7 */ - FF (b, c, d, a, x[ 7], S14); /* 8 */ - FF (a, b, c, d, x[ 8], S11); /* 9 */ - FF (d, a, b, c, x[ 9], S12); /* 10 */ - FF (c, d, a, b, x[10], S13); /* 11 */ - FF (b, c, d, a, x[11], S14); /* 12 */ - FF (a, b, c, d, x[12], S11); /* 13 */ - FF (d, a, b, c, x[13], S12); /* 14 */ - FF (c, d, a, b, x[14], S13); /* 15 */ - FF (b, c, d, a, x[15], S14); /* 16 */ - - /* Round 2 */ - GG (a, b, c, d, x[ 0], S21); /* 17 */ - GG (d, a, b, c, x[ 4], S22); /* 18 */ - GG (c, d, a, b, x[ 8], S23); /* 19 */ - GG (b, c, d, a, x[12], S24); /* 20 */ - GG (a, b, c, d, x[ 1], S21); /* 21 */ - GG (d, a, b, c, x[ 5], S22); /* 22 */ - GG (c, d, a, b, x[ 9], S23); /* 23 */ - GG (b, c, d, a, x[13], S24); /* 24 */ - GG (a, b, c, d, x[ 2], S21); /* 25 */ - GG (d, a, b, c, x[ 6], S22); /* 26 */ - GG (c, d, a, b, x[10], S23); /* 27 */ - GG (b, c, d, a, x[14], S24); /* 28 */ - GG (a, b, c, d, x[ 3], S21); /* 29 */ - GG (d, a, b, c, x[ 7], S22); /* 30 */ - GG (c, d, a, b, x[11], S23); /* 31 */ - GG (b, c, d, a, x[15], S24); /* 32 */ - - /* Round 3 */ - HH (a, b, c, d, x[ 0], S31); /* 33 */ - HH (d, a, b, c, x[ 8], S32); /* 34 */ - HH (c, d, a, b, x[ 4], S33); /* 35 */ - HH (b, c, d, a, x[12], S34); /* 36 */ - HH (a, b, c, d, x[ 2], S31); /* 37 */ - HH (d, a, b, c, x[10], S32); /* 38 */ - HH (c, d, a, b, x[ 6], S33); /* 39 */ - HH (b, c, d, a, x[14], S34); /* 40 */ - HH (a, b, c, d, x[ 1], S31); /* 41 */ - HH (d, a, b, c, x[ 9], S32); /* 42 */ - HH (c, d, a, b, x[ 5], S33); /* 43 */ - HH (b, c, d, a, x[13], S34); /* 44 */ - HH (a, b, c, d, x[ 3], S31); /* 45 */ - HH (d, a, b, c, x[11], S32); /* 46 */ - HH (c, d, a, b, x[ 7], S33); /* 47 */ - HH (b, c, d, a, x[15], S34); /* 48 */ - - - /* Update our state */ - md->md4.state[0] = md->md4.state[0] + a; - md->md4.state[1] = md->md4.state[1] + b; - md->md4.state[2] = md->md4.state[2] + c; - md->md4.state[3] = md->md4.state[3] + d; - - return CRYPT_OK; -} - -#ifdef LTC_CLEAN_STACK -static int md4_compress(hash_state *md, unsigned char *buf) -{ - int err; - err = _md4_compress(md, buf); - burn_stack(sizeof(ulong32) * 20 + sizeof(int)); - return err; -} -#endif - -/** - Initialize the hash state - @param md The hash state you wish to initialize - @return CRYPT_OK if successful -*/ -int md4_init(hash_state * md) -{ - LTC_ARGCHK(md != NULL); - md->md4.state[0] = 0x67452301UL; - md->md4.state[1] = 0xefcdab89UL; - md->md4.state[2] = 0x98badcfeUL; - md->md4.state[3] = 0x10325476UL; - md->md4.length = 0; - md->md4.curlen = 0; - return CRYPT_OK; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful -*/ -HASH_PROCESS(md4_process, md4_compress, md4, 64) - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (16 bytes) - @return CRYPT_OK if successful -*/ -int md4_done(hash_state * md, unsigned char *out) -{ - int i; - - LTC_ARGCHK(md != NULL); - LTC_ARGCHK(out != NULL); - - if (md->md4.curlen >= sizeof(md->md4.buf)) { - return CRYPT_INVALID_ARG; - } - - /* increase the length of the message */ - md->md4.length += md->md4.curlen * 8; - - /* append the '1' bit */ - md->md4.buf[md->md4.curlen++] = (unsigned char)0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (md->md4.curlen > 56) { - while (md->md4.curlen < 64) { - md->md4.buf[md->md4.curlen++] = (unsigned char)0; - } - md4_compress(md, md->md4.buf); - md->md4.curlen = 0; - } - - /* pad upto 56 bytes of zeroes */ - while (md->md4.curlen < 56) { - md->md4.buf[md->md4.curlen++] = (unsigned char)0; - } - - /* store length */ - STORE64L(md->md4.length, md->md4.buf+56); - md4_compress(md, md->md4.buf); - - /* copy output */ - for (i = 0; i < 4; i++) { - STORE32L(md->md4.state[i], out+(4*i)); - } -#ifdef LTC_CLEAN_STACK - zeromem(md, sizeof(hash_state)); -#endif - return CRYPT_OK; -} - -/** - Self-test the hash - @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled -*/ -int md4_test(void) -{ - #ifndef LTC_TEST - return CRYPT_NOP; - #else - static const struct md4_test_case { - char *input; - unsigned char digest[16]; - } cases[] = { - { "", - {0x31, 0xd6, 0xcf, 0xe0, 0xd1, 0x6a, 0xe9, 0x31, - 0xb7, 0x3c, 0x59, 0xd7, 0xe0, 0xc0, 0x89, 0xc0} }, - { "a", - {0xbd, 0xe5, 0x2c, 0xb3, 0x1d, 0xe3, 0x3e, 0x46, - 0x24, 0x5e, 0x05, 0xfb, 0xdb, 0xd6, 0xfb, 0x24} }, - { "abc", - {0xa4, 0x48, 0x01, 0x7a, 0xaf, 0x21, 0xd8, 0x52, - 0x5f, 0xc1, 0x0a, 0xe8, 0x7a, 0xa6, 0x72, 0x9d} }, - { "message digest", - {0xd9, 0x13, 0x0a, 0x81, 0x64, 0x54, 0x9f, 0xe8, - 0x18, 0x87, 0x48, 0x06, 0xe1, 0xc7, 0x01, 0x4b} }, - { "abcdefghijklmnopqrstuvwxyz", - {0xd7, 0x9e, 0x1c, 0x30, 0x8a, 0xa5, 0xbb, 0xcd, - 0xee, 0xa8, 0xed, 0x63, 0xdf, 0x41, 0x2d, 0xa9} }, - { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - {0x04, 0x3f, 0x85, 0x82, 0xf2, 0x41, 0xdb, 0x35, - 0x1c, 0xe6, 0x27, 0xe1, 0x53, 0xe7, 0xf0, 0xe4} }, - { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", - {0xe3, 0x3b, 0x4d, 0xdc, 0x9c, 0x38, 0xf2, 0x19, - 0x9c, 0x3e, 0x7b, 0x16, 0x4f, 0xcc, 0x05, 0x36} }, - }; - int i; - hash_state md; - unsigned char digest[16]; - - for(i = 0; i < (int)(sizeof(cases) / sizeof(cases[0])); i++) { - md4_init(&md); - md4_process(&md, (unsigned char *)cases[i].input, (unsigned long)strlen(cases[i].input)); - md4_done(&md, digest); - if (XMEMCMP(digest, cases[i].digest, 16) != 0) { - return CRYPT_FAIL_TESTVECTOR; - } - - } - return CRYPT_OK; - #endif -} - -#endif - - - -/* $Source: /cvs/libtom/libtomcrypt/src/hashes/md4.c,v $ */ -/* $Revision: 1.10 $ */ -/* $Date: 2007/05/12 14:25:28 $ */ diff --git a/crypto/md5.c b/crypto/md5.c deleted file mode 100644 index 78a861af..00000000 --- a/crypto/md5.c +++ /dev/null @@ -1,368 +0,0 @@ -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org - */ -#include "tomcrypt.h" - - -/** - @file md5.c - LTC_MD5 hash function by Tom St Denis -*/ - -#ifdef LTC_MD5 - -const struct ltc_hash_descriptor md5_desc = -{ - "md5", - 3, - 16, - 64, - - /* OID */ - { 1, 2, 840, 113549, 2, 5, }, - 6, - - &md5_init, - &md5_process, - &md5_done, - &md5_test, - NULL -}; - -#define F(x,y,z) (z ^ (x & (y ^ z))) -#define G(x,y,z) (y ^ (z & (y ^ x))) -#define H(x,y,z) (x^y^z) -#define I(x,y,z) (y^(x|(~z))) - -#ifdef LTC_SMALL_CODE - -#define FF(a,b,c,d,M,s,t) \ - a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b; - -#define GG(a,b,c,d,M,s,t) \ - a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b; - -#define HH(a,b,c,d,M,s,t) \ - a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b; - -#define II(a,b,c,d,M,s,t) \ - a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b; - -static const unsigned char Worder[64] = { - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12, - 5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2, - 0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9 -}; - -static const unsigned char Rorder[64] = { - 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22, - 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20, - 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23, - 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21 -}; - -static const ulong32 Korder[64] = { -0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL, 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL, -0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL, 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL, -0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL, 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL, -0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL, 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL, -0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL, 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL, -0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL, 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL, -0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL, 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL, -0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL, 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL -}; - -#else - -#define FF(a,b,c,d,M,s,t) \ - a = (a + F(b,c,d) + M + t); a = ROLc(a, s) + b; - -#define GG(a,b,c,d,M,s,t) \ - a = (a + G(b,c,d) + M + t); a = ROLc(a, s) + b; - -#define HH(a,b,c,d,M,s,t) \ - a = (a + H(b,c,d) + M + t); a = ROLc(a, s) + b; - -#define II(a,b,c,d,M,s,t) \ - a = (a + I(b,c,d) + M + t); a = ROLc(a, s) + b; - - -#endif - -#ifdef LTC_CLEAN_STACK -static int _md5_compress(hash_state *md, unsigned char *buf) -#else -static int md5_compress(hash_state *md, unsigned char *buf) -#endif -{ - ulong32 i, W[16], a, b, c, d; -#ifdef LTC_SMALL_CODE - ulong32 t; -#endif - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) { - LOAD32L(W[i], buf + (4*i)); - } - - /* copy state */ - a = md->md5.state[0]; - b = md->md5.state[1]; - c = md->md5.state[2]; - d = md->md5.state[3]; - -#ifdef LTC_SMALL_CODE - for (i = 0; i < 16; ++i) { - FF(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]); - t = d; d = c; c = b; b = a; a = t; - } - - for (; i < 32; ++i) { - GG(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]); - t = d; d = c; c = b; b = a; a = t; - } - - for (; i < 48; ++i) { - HH(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]); - t = d; d = c; c = b; b = a; a = t; - } - - for (; i < 64; ++i) { - II(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]); - t = d; d = c; c = b; b = a; a = t; - } - -#else - FF(a,b,c,d,W[0],7,0xd76aa478UL) - FF(d,a,b,c,W[1],12,0xe8c7b756UL) - FF(c,d,a,b,W[2],17,0x242070dbUL) - FF(b,c,d,a,W[3],22,0xc1bdceeeUL) - FF(a,b,c,d,W[4],7,0xf57c0fafUL) - FF(d,a,b,c,W[5],12,0x4787c62aUL) - FF(c,d,a,b,W[6],17,0xa8304613UL) - FF(b,c,d,a,W[7],22,0xfd469501UL) - FF(a,b,c,d,W[8],7,0x698098d8UL) - FF(d,a,b,c,W[9],12,0x8b44f7afUL) - FF(c,d,a,b,W[10],17,0xffff5bb1UL) - FF(b,c,d,a,W[11],22,0x895cd7beUL) - FF(a,b,c,d,W[12],7,0x6b901122UL) - FF(d,a,b,c,W[13],12,0xfd987193UL) - FF(c,d,a,b,W[14],17,0xa679438eUL) - FF(b,c,d,a,W[15],22,0x49b40821UL) - GG(a,b,c,d,W[1],5,0xf61e2562UL) - GG(d,a,b,c,W[6],9,0xc040b340UL) - GG(c,d,a,b,W[11],14,0x265e5a51UL) - GG(b,c,d,a,W[0],20,0xe9b6c7aaUL) - GG(a,b,c,d,W[5],5,0xd62f105dUL) - GG(d,a,b,c,W[10],9,0x02441453UL) - GG(c,d,a,b,W[15],14,0xd8a1e681UL) - GG(b,c,d,a,W[4],20,0xe7d3fbc8UL) - GG(a,b,c,d,W[9],5,0x21e1cde6UL) - GG(d,a,b,c,W[14],9,0xc33707d6UL) - GG(c,d,a,b,W[3],14,0xf4d50d87UL) - GG(b,c,d,a,W[8],20,0x455a14edUL) - GG(a,b,c,d,W[13],5,0xa9e3e905UL) - GG(d,a,b,c,W[2],9,0xfcefa3f8UL) - GG(c,d,a,b,W[7],14,0x676f02d9UL) - GG(b,c,d,a,W[12],20,0x8d2a4c8aUL) - HH(a,b,c,d,W[5],4,0xfffa3942UL) - HH(d,a,b,c,W[8],11,0x8771f681UL) - HH(c,d,a,b,W[11],16,0x6d9d6122UL) - HH(b,c,d,a,W[14],23,0xfde5380cUL) - HH(a,b,c,d,W[1],4,0xa4beea44UL) - HH(d,a,b,c,W[4],11,0x4bdecfa9UL) - HH(c,d,a,b,W[7],16,0xf6bb4b60UL) - HH(b,c,d,a,W[10],23,0xbebfbc70UL) - HH(a,b,c,d,W[13],4,0x289b7ec6UL) - HH(d,a,b,c,W[0],11,0xeaa127faUL) - HH(c,d,a,b,W[3],16,0xd4ef3085UL) - HH(b,c,d,a,W[6],23,0x04881d05UL) - HH(a,b,c,d,W[9],4,0xd9d4d039UL) - HH(d,a,b,c,W[12],11,0xe6db99e5UL) - HH(c,d,a,b,W[15],16,0x1fa27cf8UL) - HH(b,c,d,a,W[2],23,0xc4ac5665UL) - II(a,b,c,d,W[0],6,0xf4292244UL) - II(d,a,b,c,W[7],10,0x432aff97UL) - II(c,d,a,b,W[14],15,0xab9423a7UL) - II(b,c,d,a,W[5],21,0xfc93a039UL) - II(a,b,c,d,W[12],6,0x655b59c3UL) - II(d,a,b,c,W[3],10,0x8f0ccc92UL) - II(c,d,a,b,W[10],15,0xffeff47dUL) - II(b,c,d,a,W[1],21,0x85845dd1UL) - II(a,b,c,d,W[8],6,0x6fa87e4fUL) - II(d,a,b,c,W[15],10,0xfe2ce6e0UL) - II(c,d,a,b,W[6],15,0xa3014314UL) - II(b,c,d,a,W[13],21,0x4e0811a1UL) - II(a,b,c,d,W[4],6,0xf7537e82UL) - II(d,a,b,c,W[11],10,0xbd3af235UL) - II(c,d,a,b,W[2],15,0x2ad7d2bbUL) - II(b,c,d,a,W[9],21,0xeb86d391UL) -#endif - - md->md5.state[0] = md->md5.state[0] + a; - md->md5.state[1] = md->md5.state[1] + b; - md->md5.state[2] = md->md5.state[2] + c; - md->md5.state[3] = md->md5.state[3] + d; - - return CRYPT_OK; -} - -#ifdef LTC_CLEAN_STACK -static int md5_compress(hash_state *md, unsigned char *buf) -{ - int err; - err = _md5_compress(md, buf); - burn_stack(sizeof(ulong32) * 21); - return err; -} -#endif - -/** - Initialize the hash state - @param md The hash state you wish to initialize - @return CRYPT_OK if successful -*/ -int md5_init(hash_state * md) -{ - LTC_ARGCHK(md != NULL); - md->md5.state[0] = 0x67452301UL; - md->md5.state[1] = 0xefcdab89UL; - md->md5.state[2] = 0x98badcfeUL; - md->md5.state[3] = 0x10325476UL; - md->md5.curlen = 0; - md->md5.length = 0; - return CRYPT_OK; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful -*/ -HASH_PROCESS(md5_process, md5_compress, md5, 64) - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (16 bytes) - @return CRYPT_OK if successful -*/ -int md5_done(hash_state * md, unsigned char *out) -{ - int i; - - LTC_ARGCHK(md != NULL); - LTC_ARGCHK(out != NULL); - - if (md->md5.curlen >= sizeof(md->md5.buf)) { - return CRYPT_INVALID_ARG; - } - - - /* increase the length of the message */ - md->md5.length += md->md5.curlen * 8; - - /* append the '1' bit */ - md->md5.buf[md->md5.curlen++] = (unsigned char)0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (md->md5.curlen > 56) { - while (md->md5.curlen < 64) { - md->md5.buf[md->md5.curlen++] = (unsigned char)0; - } - md5_compress(md, md->md5.buf); - md->md5.curlen = 0; - } - - /* pad upto 56 bytes of zeroes */ - while (md->md5.curlen < 56) { - md->md5.buf[md->md5.curlen++] = (unsigned char)0; - } - - /* store length */ - STORE64L(md->md5.length, md->md5.buf+56); - md5_compress(md, md->md5.buf); - - /* copy output */ - for (i = 0; i < 4; i++) { - STORE32L(md->md5.state[i], out+(4*i)); - } -#ifdef LTC_CLEAN_STACK - zeromem(md, sizeof(hash_state)); -#endif - return CRYPT_OK; -} - -/** - Self-test the hash - @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled -*/ -int md5_test(void) -{ - #ifndef LTC_TEST - return CRYPT_NOP; - #else - static const struct { - char *msg; - unsigned char hash[16]; - } tests[] = { - { "", - { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, - 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } }, - { "a", - {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, - 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } }, - { "abc", - { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, - 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } }, - { "message digest", - { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, - 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } }, - { "abcdefghijklmnopqrstuvwxyz", - { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, - 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } }, - { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", - { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, - 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } }, - { "12345678901234567890123456789012345678901234567890123456789012345678901234567890", - { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, - 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }, - { NULL, { 0 } } - }; - - int i; - unsigned char tmp[16]; - hash_state md; - - for (i = 0; tests[i].msg != NULL; i++) { - md5_init(&md); - md5_process(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg)); - md5_done(&md, tmp); - if (XMEMCMP(tmp, tests[i].hash, 16) != 0) { - return CRYPT_FAIL_TESTVECTOR; - } - } - return CRYPT_OK; - #endif -} - -#endif - - - -/* $Source: /cvs/libtom/libtomcrypt/src/hashes/md5.c,v $ */ -/* $Revision: 1.10 $ */ -/* $Date: 2007/05/12 14:25:28 $ */ diff --git a/crypto/sha1.c b/crypto/sha1.c deleted file mode 100644 index a1a216e6..00000000 --- a/crypto/sha1.c +++ /dev/null @@ -1,288 +0,0 @@ -/* LibTomCrypt, modular cryptographic library -- Tom St Denis - * - * LibTomCrypt is a library that provides various cryptographic - * algorithms in a highly modular and flexible manner. - * - * The library is free for all purposes without any express - * guarantee it works. - * - * Tom St Denis, tomstdenis@gmail.com, http://libtom.org - */ -#include "tomcrypt.h" - -/** - @file sha1.c - LTC_SHA1 code by Tom St Denis -*/ - - -#ifdef LTC_SHA1 - -const struct ltc_hash_descriptor sha1_desc = -{ - "sha1", - 2, - 20, - 64, - - /* OID */ - { 1, 3, 14, 3, 2, 26, }, - 6, - - &sha1_init, - &sha1_process, - &sha1_done, - &sha1_test, - NULL -}; - -#define F0(x,y,z) (z ^ (x & (y ^ z))) -#define F1(x,y,z) (x ^ y ^ z) -#define F2(x,y,z) ((x & y) | (z & (x | y))) -#define F3(x,y,z) (x ^ y ^ z) - -#ifdef LTC_CLEAN_STACK -static int _sha1_compress(hash_state *md, unsigned char *buf) -#else -static int sha1_compress(hash_state *md, unsigned char *buf) -#endif -{ - ulong32 a,b,c,d,e,W[80],i; -#ifdef LTC_SMALL_CODE - ulong32 t; -#endif - - /* copy the state into 512-bits into W[0..15] */ - for (i = 0; i < 16; i++) { - LOAD32H(W[i], buf + (4*i)); - } - - /* copy state */ - a = md->sha1.state[0]; - b = md->sha1.state[1]; - c = md->sha1.state[2]; - d = md->sha1.state[3]; - e = md->sha1.state[4]; - - /* expand it */ - for (i = 16; i < 80; i++) { - W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1); - } - - /* compress */ - /* round one */ - #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30); - #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30); - #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30); - #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30); - -#ifdef LTC_SMALL_CODE - - for (i = 0; i < 20; ) { - FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; - } - - for (; i < 40; ) { - FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; - } - - for (; i < 60; ) { - FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; - } - - for (; i < 80; ) { - FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t; - } - -#else - - for (i = 0; i < 20; ) { - FF0(a,b,c,d,e,i++); - FF0(e,a,b,c,d,i++); - FF0(d,e,a,b,c,i++); - FF0(c,d,e,a,b,i++); - FF0(b,c,d,e,a,i++); - } - - /* round two */ - for (; i < 40; ) { - FF1(a,b,c,d,e,i++); - FF1(e,a,b,c,d,i++); - FF1(d,e,a,b,c,i++); - FF1(c,d,e,a,b,i++); - FF1(b,c,d,e,a,i++); - } - - /* round three */ - for (; i < 60; ) { - FF2(a,b,c,d,e,i++); - FF2(e,a,b,c,d,i++); - FF2(d,e,a,b,c,i++); - FF2(c,d,e,a,b,i++); - FF2(b,c,d,e,a,i++); - } - - /* round four */ - for (; i < 80; ) { - FF3(a,b,c,d,e,i++); - FF3(e,a,b,c,d,i++); - FF3(d,e,a,b,c,i++); - FF3(c,d,e,a,b,i++); - FF3(b,c,d,e,a,i++); - } -#endif - - #undef FF0 - #undef FF1 - #undef FF2 - #undef FF3 - - /* store */ - md->sha1.state[0] = md->sha1.state[0] + a; - md->sha1.state[1] = md->sha1.state[1] + b; - md->sha1.state[2] = md->sha1.state[2] + c; - md->sha1.state[3] = md->sha1.state[3] + d; - md->sha1.state[4] = md->sha1.state[4] + e; - - return CRYPT_OK; -} - -#ifdef LTC_CLEAN_STACK -static int sha1_compress(hash_state *md, unsigned char *buf) -{ - int err; - err = _sha1_compress(md, buf); - burn_stack(sizeof(ulong32) * 87); - return err; -} -#endif - -/** - Initialize the hash state - @param md The hash state you wish to initialize - @return CRYPT_OK if successful -*/ -int sha1_init(hash_state * md) -{ - LTC_ARGCHK(md != NULL); - md->sha1.state[0] = 0x67452301UL; - md->sha1.state[1] = 0xefcdab89UL; - md->sha1.state[2] = 0x98badcfeUL; - md->sha1.state[3] = 0x10325476UL; - md->sha1.state[4] = 0xc3d2e1f0UL; - md->sha1.curlen = 0; - md->sha1.length = 0; - return CRYPT_OK; -} - -/** - Process a block of memory though the hash - @param md The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful -*/ -HASH_PROCESS(sha1_process, sha1_compress, sha1, 64) - -/** - Terminate the hash to get the digest - @param md The hash state - @param out [out] The destination of the hash (20 bytes) - @return CRYPT_OK if successful -*/ -int sha1_done(hash_state * md, unsigned char *out) -{ - int i; - - LTC_ARGCHK(md != NULL); - LTC_ARGCHK(out != NULL); - - if (md->sha1.curlen >= sizeof(md->sha1.buf)) { - return CRYPT_INVALID_ARG; - } - - /* increase the length of the message */ - md->sha1.length += md->sha1.curlen * 8; - - /* append the '1' bit */ - md->sha1.buf[md->sha1.curlen++] = (unsigned char)0x80; - - /* if the length is currently above 56 bytes we append zeros - * then compress. Then we can fall back to padding zeros and length - * encoding like normal. - */ - if (md->sha1.curlen > 56) { - while (md->sha1.curlen < 64) { - md->sha1.buf[md->sha1.curlen++] = (unsigned char)0; - } - sha1_compress(md, md->sha1.buf); - md->sha1.curlen = 0; - } - - /* pad upto 56 bytes of zeroes */ - while (md->sha1.curlen < 56) { - md->sha1.buf[md->sha1.curlen++] = (unsigned char)0; - } - - /* store length */ - STORE64H(md->sha1.length, md->sha1.buf+56); - sha1_compress(md, md->sha1.buf); - - /* copy output */ - for (i = 0; i < 5; i++) { - STORE32H(md->sha1.state[i], out+(4*i)); - } -#ifdef LTC_CLEAN_STACK - zeromem(md, sizeof(hash_state)); -#endif - return CRYPT_OK; -} - -/** - Self-test the hash - @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled -*/ -int sha1_test(void) -{ - #ifndef LTC_TEST - return CRYPT_NOP; - #else - static const struct { - char *msg; - unsigned char hash[20]; - } tests[] = { - { "abc", - { 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a, - 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c, - 0x9c, 0xd0, 0xd8, 0x9d } - }, - { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", - { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, - 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, - 0xE5, 0x46, 0x70, 0xF1 } - } - }; - - int i; - unsigned char tmp[20]; - hash_state md; - - for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { - sha1_init(&md); - sha1_process(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg)); - sha1_done(&md, tmp); - if (XMEMCMP(tmp, tests[i].hash, 20) != 0) { - return CRYPT_FAIL_TESTVECTOR; - } - } - return CRYPT_OK; - #endif -} - -#endif - - - -/* $Source: /cvs/libtom/libtomcrypt/src/hashes/sha1.c,v $ */ -/* $Revision: 1.10 $ */ -/* $Date: 2007/05/12 14:25:28 $ */ diff --git a/crypto/tomcrypt.h b/crypto/tomcrypt.h deleted file mode 100644 index 029e2df7..00000000 --- a/crypto/tomcrypt.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef TOMCRYPT_H_ -#define TOMCRYPT_H_ -#include <assert.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> -#include <ctype.h> -#include <limits.h> - -/* use configuration data */ -#include "tomcrypt_custom.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* version */ -#define CRYPT 0x0117 -#define SCRYPT "1.17" - -/* max size of either a cipher/hash block or symmetric key [largest of the two] */ -#define MAXBLOCKSIZE 128 - -/* descriptor table size */ -#define TAB_SIZE 32 - -/* error codes [will be expanded in future releases] */ -enum { - CRYPT_OK=0, /* Result OK */ - CRYPT_ERROR, /* Generic Error */ - CRYPT_NOP, /* Not a failure but no operation was performed */ - - CRYPT_INVALID_KEYSIZE, /* Invalid key size given */ - CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */ - CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */ - - CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */ - CRYPT_INVALID_PACKET, /* Invalid input packet given */ - - CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */ - CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */ - - CRYPT_INVALID_CIPHER, /* Invalid cipher specified */ - CRYPT_INVALID_HASH, /* Invalid hash specified */ - CRYPT_INVALID_PRNG, /* Invalid PRNG specified */ - - CRYPT_MEM, /* Out of memory */ - - CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */ - CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */ - - CRYPT_INVALID_ARG, /* Generic invalid argument */ - CRYPT_FILE_NOTFOUND, /* File Not Found */ - - CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */ - CRYPT_PK_INVALID_SYSTEM,/* Invalid PK system specified */ - CRYPT_PK_DUP, /* Duplicate key already in key ring */ - CRYPT_PK_NOT_FOUND, /* Key not found in keyring */ - CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */ - - CRYPT_INVALID_PRIME_SIZE,/* Invalid size of prime requested */ - CRYPT_PK_INVALID_PADDING /* Invalid padding on input */ -}; - -#include "tomcrypt_cfg.h" -#include "tomcrypt_macros.h" -#include "tomcrypt_cipher.h" -#include "tomcrypt_hash.h" -//#include <tomcrypt_mac.h> -//#include <tomcrypt_prng.h> -//#include <tomcrypt_pk.h> -//#include <tomcrypt_math.h> -//#include <tomcrypt_misc.h> -#include "tomcrypt_argchk.h" -//#include <tomcrypt_pkcs.h> - -#ifdef __cplusplus - } -#endif - -#endif /* TOMCRYPT_H_ */ - - -/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt.h,v $ */ -/* $Revision: 1.21 $ */ -/* $Date: 2006/12/16 19:34:05 $ */ diff --git a/crypto/tomcrypt_argchk.h b/crypto/tomcrypt_argchk.h deleted file mode 100644 index aed53dbe..00000000 --- a/crypto/tomcrypt_argchk.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Defines the LTC_ARGCHK macro used within the library */ -/* ARGTYPE is defined in mycrypt_cfg.h */ -#if ARGTYPE == 0 - -#include <signal.h> - -/* this is the default LibTomCrypt macro */ -void crypt_argchk(char *v, char *s, int d); -#define LTC_ARGCHK(x) if (!(x)) { crypt_argchk(#x, __FILE__, __LINE__); } -#define LTC_ARGCHKVD(x) LTC_ARGCHK(x) - -#elif ARGTYPE == 1 - -/* fatal type of error */ -#define LTC_ARGCHK(x) assert((x)) -#define LTC_ARGCHKVD(x) LTC_ARGCHK(x) - -#elif ARGTYPE == 2 - -#define LTC_ARGCHK(x) if (!(x)) { fprintf(stderr, "\nwarning: ARGCHK failed at %s:%d\n", __FILE__, __LINE__); } -#define LTC_ARGCHKVD(x) LTC_ARGCHK(x) - -#elif ARGTYPE == 3 - -#define LTC_ARGCHK(x) -#define LTC_ARGCHKVD(x) LTC_ARGCHK(x) - -#elif ARGTYPE == 4 - -#define LTC_ARGCHK(x) if (!(x)) return CRYPT_INVALID_ARG; -#define LTC_ARGCHKVD(x) if (!(x)) return; - -#endif - - -/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_argchk.h,v $ */ -/* $Revision: 1.5 $ */ -/* $Date: 2006/08/27 20:50:21 $ */ diff --git a/crypto/tomcrypt_cfg.h b/crypto/tomcrypt_cfg.h deleted file mode 100644 index cc2df7a3..00000000 --- a/crypto/tomcrypt_cfg.h +++ /dev/null @@ -1,136 +0,0 @@ -/* This is the build config file. - * - * With this you can setup what to inlcude/exclude automatically during any build. Just comment - * out the line that #define's the word for the thing you want to remove. phew! - */ - -#ifndef TOMCRYPT_CFG_H -#define TOMCRYPT_CFG_H - -#if defined(_WIN32) || defined(_MSC_VER) -#define LTC_CALL __cdecl -#else -#ifndef LTC_CALL - #define LTC_CALL -#endif -#endif - -#ifndef LTC_EXPORT -#define LTC_EXPORT -#endif - -/* certain platforms use macros for these, making the prototypes broken */ -#ifndef LTC_NO_PROTOTYPES - -/* you can change how memory allocation works ... */ -LTC_EXPORT void * LTC_CALL XMALLOC(size_t n); -LTC_EXPORT void * LTC_CALL XREALLOC(void *p, size_t n); -LTC_EXPORT void * LTC_CALL XCALLOC(size_t n, size_t s); -LTC_EXPORT void LTC_CALL XFREE(void *p); - -LTC_EXPORT void LTC_CALL XQSORT(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *)); - - -/* change the clock function too */ -LTC_EXPORT clock_t LTC_CALL XCLOCK(void); - -/* various other functions */ -LTC_EXPORT void * LTC_CALL XMEMCPY(void *dest, const void *src, size_t n); -LTC_EXPORT int LTC_CALL XMEMCMP(const void *s1, const void *s2, size_t n); -LTC_EXPORT void * LTC_CALL XMEMSET(void *s, int c, size_t n); - -LTC_EXPORT int LTC_CALL XSTRCMP(const char *s1, const char *s2); - -#endif - -/* type of argument checking, 0=default, 1=fatal and 2=error+continue, 3=nothing */ -#ifndef ARGTYPE - #define ARGTYPE 0 -#endif - -/* Controls endianess and size of registers. Leave uncommented to get platform neutral [slower] code - * - * Note: in order to use the optimized macros your platform must support unaligned 32 and 64 bit read/writes. - * The x86 platforms allow this but some others [ARM for instance] do not. On those platforms you **MUST** - * use the portable [slower] macros. - */ - -/* detect x86-32 machines somewhat */ -#if !defined(__STRICT_ANSI__) && (defined(INTEL_CC) || (defined(_MSC_VER) && defined(WIN32)) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__)))) - #define ENDIAN_LITTLE - #define ENDIAN_32BITWORD - #define LTC_FAST - #define LTC_FAST_TYPE unsigned long -#endif - -/* detects MIPS R5900 processors (PS2) */ -#if (defined(__R5900) || defined(R5900) || defined(__R5900__)) && (defined(_mips) || defined(__mips__) || defined(mips)) - #define ENDIAN_LITTLE - #define ENDIAN_64BITWORD -#endif - -/* detect amd64 */ -#if !defined(__STRICT_ANSI__) && defined(__x86_64__) - #define ENDIAN_LITTLE - #define ENDIAN_64BITWORD - #define LTC_FAST - #define LTC_FAST_TYPE unsigned long long -#endif - -/* detect PPC32 */ -#if !defined(__STRICT_ANSI__) && defined(LTC_PPC32) - #define ENDIAN_BIG - #define ENDIAN_32BITWORD - #define LTC_FAST - #define LTC_FAST_TYPE unsigned long -#endif - -/* detect sparc and sparc64 */ -#if defined(__sparc__) - #define ENDIAN_BIG - #if defined(__arch64__) - #define ENDIAN_64BITWORD - #else - #define ENDIAN_32BITWORD - #endif -#endif - - -#ifdef LTC_NO_FAST - #ifdef LTC_FAST - #undef LTC_FAST - #endif -#endif - -/* No asm is a quick way to disable anything "not portable" */ -#ifdef LTC_NO_ASM - #undef ENDIAN_LITTLE - #undef ENDIAN_BIG - #undef ENDIAN_32BITWORD - #undef ENDIAN_64BITWORD - #undef LTC_FAST - #undef LTC_FAST_TYPE - #define LTC_NO_ROLC - #define LTC_NO_BSWAP -#endif - -/* #define ENDIAN_LITTLE */ -/* #define ENDIAN_BIG */ - -/* #define ENDIAN_32BITWORD */ -/* #define ENDIAN_64BITWORD */ - -#if (defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) && !(defined(ENDIAN_32BITWORD) || defined(ENDIAN_64BITWORD)) - #error You must specify a word size as well as endianess in tomcrypt_cfg.h -#endif - -#if !(defined(ENDIAN_BIG) || defined(ENDIAN_LITTLE)) - #define ENDIAN_NEUTRAL -#endif - -#endif - - -/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cfg.h,v $ */ -/* $Revision: 1.19 $ */ -/* $Date: 2006/12/04 02:19:48 $ */ diff --git a/crypto/tomcrypt_cipher.h b/crypto/tomcrypt_cipher.h deleted file mode 100644 index 24e1f781..00000000 --- a/crypto/tomcrypt_cipher.h +++ /dev/null @@ -1,897 +0,0 @@ -/* ---- SYMMETRIC KEY STUFF ----- - * - * We put each of the ciphers scheduled keys in their own structs then we put all of - * the key formats in one union. This makes the function prototypes easier to use. - */ -#ifdef LTC_BLOWFISH -struct blowfish_key { - ulong32 S[4][256]; - ulong32 K[18]; -}; -#endif - -#ifdef LTC_RC5 -struct rc5_key { - int rounds; - ulong32 K[50]; -}; -#endif - -#ifdef LTC_RC6 -struct rc6_key { - ulong32 K[44]; -}; -#endif - -#ifdef LTC_SAFERP -struct saferp_key { - unsigned char K[33][16]; - long rounds; -}; -#endif - -#ifdef LTC_RIJNDAEL -struct rijndael_key { - ulong32 eK[60], dK[60]; - int Nr; -}; -#endif - -#ifdef LTC_KSEED -struct kseed_key { - ulong32 K[32], dK[32]; -}; -#endif - -#ifdef LTC_KASUMI -struct kasumi_key { - ulong32 KLi1[8], KLi2[8], - KOi1[8], KOi2[8], KOi3[8], - KIi1[8], KIi2[8], KIi3[8]; -}; -#endif - -#ifdef LTC_XTEA -struct xtea_key { - unsigned long A[32], B[32]; -}; -#endif - -#ifdef LTC_TWOFISH -#ifndef LTC_TWOFISH_SMALL - struct twofish_key { - ulong32 S[4][256], K[40]; - }; -#else - struct twofish_key { - ulong32 K[40]; - unsigned char S[32], start; - }; -#endif -#endif - -#ifdef LTC_SAFER -#define LTC_SAFER_K64_DEFAULT_NOF_ROUNDS 6 -#define LTC_SAFER_K128_DEFAULT_NOF_ROUNDS 10 -#define LTC_SAFER_SK64_DEFAULT_NOF_ROUNDS 8 -#define LTC_SAFER_SK128_DEFAULT_NOF_ROUNDS 10 -#define LTC_SAFER_MAX_NOF_ROUNDS 13 -#define LTC_SAFER_BLOCK_LEN 8 -#define LTC_SAFER_KEY_LEN (1 + LTC_SAFER_BLOCK_LEN * (1 + 2 * LTC_SAFER_MAX_NOF_ROUNDS)) -typedef unsigned char safer_block_t[LTC_SAFER_BLOCK_LEN]; -typedef unsigned char safer_key_t[LTC_SAFER_KEY_LEN]; -struct safer_key { safer_key_t key; }; -#endif - -#ifdef LTC_RC2 -struct rc2_key { unsigned xkey[64]; }; -#endif - -#ifdef LTC_DES -struct des_key { - ulong32 ek[32], dk[32]; -}; -#ifdef LTC_DES3 -struct des3_key { - ulong32 ek[3][32], dk[3][32]; -}; -#endif -#endif - -#ifdef LTC_CAST5 -struct cast5_key { - ulong32 K[32], keylen; -}; -#endif - -#ifdef LTC_NOEKEON -struct noekeon_key { - ulong32 K[4], dK[4]; -}; -#endif - -#ifdef LTC_SKIPJACK -struct skipjack_key { - unsigned char key[10]; -}; -#endif - -#ifdef LTC_KHAZAD -struct khazad_key { - ulong64 roundKeyEnc[8 + 1]; - ulong64 roundKeyDec[8 + 1]; -}; -#endif - -#ifdef LTC_ANUBIS -struct anubis_key { - int keyBits; - int R; - ulong32 roundKeyEnc[18 + 1][4]; - ulong32 roundKeyDec[18 + 1][4]; -}; -#endif - -#ifdef LTC_MULTI2 -struct multi2_key { - int N; - ulong32 uk[8]; -}; -#endif - -typedef union Symmetric_key { -#ifdef LTC_DES - struct des_key des; -#ifdef LTC_DES3 - struct des3_key des3; -#endif -#endif -#ifdef LTC_RC2 - struct rc2_key rc2; -#endif -#ifdef LTC_SAFER - struct safer_key safer; -#endif -#ifdef LTC_TWOFISH - struct twofish_key twofish; -#endif -#ifdef LTC_BLOWFISH - struct blowfish_key blowfish; -#endif -#ifdef LTC_RC5 - struct rc5_key rc5; -#endif -#ifdef LTC_RC6 - struct rc6_key rc6; -#endif -#ifdef LTC_SAFERP - struct saferp_key saferp; -#endif -#ifdef LTC_RIJNDAEL - struct rijndael_key rijndael; -#endif -#ifdef LTC_XTEA - struct xtea_key xtea; -#endif -#ifdef LTC_CAST5 - struct cast5_key cast5; -#endif -#ifdef LTC_NOEKEON - struct noekeon_key noekeon; -#endif -#ifdef LTC_SKIPJACK - struct skipjack_key skipjack; -#endif -#ifdef LTC_KHAZAD - struct khazad_key khazad; -#endif -#ifdef LTC_ANUBIS - struct anubis_key anubis; -#endif -#ifdef LTC_KSEED - struct kseed_key kseed; -#endif -#ifdef LTC_KASUMI - struct kasumi_key kasumi; -#endif -#ifdef LTC_MULTI2 - struct multi2_key multi2; -#endif - void *data; -} symmetric_key; - -#ifdef LTC_ECB_MODE -/** A block cipher ECB structure */ -typedef struct { - /** The index of the cipher chosen */ - int cipher, - /** The block size of the given cipher */ - blocklen; - /** The scheduled key */ - symmetric_key key; -} symmetric_ECB; -#endif - -#ifdef LTC_CFB_MODE -/** A block cipher CFB structure */ -typedef struct { - /** The index of the cipher chosen */ - int cipher, - /** The block size of the given cipher */ - blocklen, - /** The padding offset */ - padlen; - /** The current IV */ - unsigned char IV[MAXBLOCKSIZE], - /** The pad used to encrypt/decrypt */ - pad[MAXBLOCKSIZE]; - /** The scheduled key */ - symmetric_key key; -} symmetric_CFB; -#endif - -#ifdef LTC_OFB_MODE -/** A block cipher OFB structure */ -typedef struct { - /** The index of the cipher chosen */ - int cipher, - /** The block size of the given cipher */ - blocklen, - /** The padding offset */ - padlen; - /** The current IV */ - unsigned char IV[MAXBLOCKSIZE]; - /** The scheduled key */ - symmetric_key key; -} symmetric_OFB; -#endif - -#ifdef LTC_CBC_MODE -/** A block cipher CBC structure */ -typedef struct { - /** The index of the cipher chosen */ - int cipher, - /** The block size of the given cipher */ - blocklen; - /** The current IV */ - unsigned char IV[MAXBLOCKSIZE]; - /** The scheduled key */ - symmetric_key key; -} symmetric_CBC; -#endif - - -#ifdef LTC_CTR_MODE -/** A block cipher CTR structure */ -typedef struct { - /** The index of the cipher chosen */ - int cipher, - /** The block size of the given cipher */ - blocklen, - /** The padding offset */ - padlen, - /** The mode (endianess) of the CTR, 0==little, 1==big */ - mode, - /** counter width */ - ctrlen; - - /** The counter */ - unsigned char ctr[MAXBLOCKSIZE], - /** The pad used to encrypt/decrypt */ - pad[MAXBLOCKSIZE]; - /** The scheduled key */ - symmetric_key key; -} symmetric_CTR; -#endif - - -#ifdef LTC_LRW_MODE -/** A LRW structure */ -typedef struct { - /** The index of the cipher chosen (must be a 128-bit block cipher) */ - int cipher; - - /** The current IV */ - unsigned char IV[16], - - /** the tweak key */ - tweak[16], - - /** The current pad, it's the product of the first 15 bytes against the tweak key */ - pad[16]; - - /** The scheduled symmetric key */ - symmetric_key key; - -#ifdef LRW_TABLES - /** The pre-computed multiplication table */ - unsigned char PC[16][256][16]; -#endif -} symmetric_LRW; -#endif - -#ifdef LTC_F8_MODE -/** A block cipher F8 structure */ -typedef struct { - /** The index of the cipher chosen */ - int cipher, - /** The block size of the given cipher */ - blocklen, - /** The padding offset */ - padlen; - /** The current IV */ - unsigned char IV[MAXBLOCKSIZE], - MIV[MAXBLOCKSIZE]; - /** Current block count */ - ulong32 blockcnt; - /** The scheduled key */ - symmetric_key key; -} symmetric_F8; -#endif - - -/** cipher descriptor table, last entry has "name == NULL" to mark the end of table */ -extern struct ltc_cipher_descriptor { - /** name of cipher */ - char *name; - /** internal ID */ - unsigned char ID; - /** min keysize (octets) */ - int min_key_length, - /** max keysize (octets) */ - max_key_length, - /** block size (octets) */ - block_length, - /** default number of rounds */ - default_rounds; - /** Setup the cipher - @param key The input symmetric key - @param keylen The length of the input key (octets) - @param num_rounds The requested number of rounds (0==default) - @param skey [out] The destination of the scheduled key - @return CRYPT_OK if successful - */ - int (*setup)(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); - /** Encrypt a block - @param pt The plaintext - @param ct [out] The ciphertext - @param skey The scheduled key - @return CRYPT_OK if successful - */ - int (*ecb_encrypt)(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); - /** Decrypt a block - @param ct The ciphertext - @param pt [out] The plaintext - @param skey The scheduled key - @return CRYPT_OK if successful - */ - int (*ecb_decrypt)(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); - /** Test the block cipher - @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled - */ - int (*test)(void); - - /** Terminate the context - @param skey The scheduled key - */ - void (*done)(symmetric_key *skey); - - /** Determine a key size - @param keysize [in/out] The size of the key desired and the suggested size - @return CRYPT_OK if successful - */ - int (*keysize)(int *keysize); - -/** Accelerators **/ - /** Accelerated ECB encryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_ecb_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, symmetric_key *skey); - - /** Accelerated ECB decryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_ecb_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, symmetric_key *skey); - - /** Accelerated CBC encryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_cbc_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, symmetric_key *skey); - - /** Accelerated CBC decryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_cbc_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, symmetric_key *skey); - - /** Accelerated CTR encryption - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param mode little or big endian counter (mode=0 or mode=1) - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_ctr_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, int mode, symmetric_key *skey); - - /** Accelerated LRW - @param pt Plaintext - @param ct Ciphertext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param tweak The LRW tweak - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_lrw_encrypt)(const unsigned char *pt, unsigned char *ct, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey); - - /** Accelerated LRW - @param ct Ciphertext - @param pt Plaintext - @param blocks The number of complete blocks to process - @param IV The initial value (input/output) - @param tweak The LRW tweak - @param skey The scheduled key context - @return CRYPT_OK if successful - */ - int (*accel_lrw_decrypt)(const unsigned char *ct, unsigned char *pt, unsigned long blocks, unsigned char *IV, const unsigned char *tweak, symmetric_key *skey); - - /** Accelerated CCM packet (one-shot) - @param key The secret key to use - @param keylen The length of the secret key (octets) - @param uskey A previously scheduled key [optional can be NULL] - @param nonce The session nonce [use once] - @param noncelen The length of the nonce - @param header The header for the session - @param headerlen The length of the header (octets) - @param pt [out] The plaintext - @param ptlen The length of the plaintext (octets) - @param ct [out] The ciphertext - @param tag [out] The destination tag - @param taglen [in/out] The max size and resulting size of the authentication tag - @param direction Encrypt or Decrypt direction (0 or 1) - @return CRYPT_OK if successful - */ - int (*accel_ccm_memory)( - const unsigned char *key, unsigned long keylen, - symmetric_key *uskey, - const unsigned char *nonce, unsigned long noncelen, - const unsigned char *header, unsigned long headerlen, - unsigned char *pt, unsigned long ptlen, - unsigned char *ct, - unsigned char *tag, unsigned long *taglen, - int direction); - - /** Accelerated GCM packet (one shot) - @param key The secret key - @param keylen The length of the secret key - @param IV The initial vector - @param IVlen The length of the initial vector - @param adata The additional authentication data (header) - @param adatalen The length of the adata - @param pt The plaintext - @param ptlen The length of the plaintext (ciphertext length is the same) - @param ct The ciphertext - @param tag [out] The MAC tag - @param taglen [in/out] The MAC tag length - @param direction Encrypt or Decrypt mode (GCM_ENCRYPT or GCM_DECRYPT) - @return CRYPT_OK on success - */ - int (*accel_gcm_memory)( - const unsigned char *key, unsigned long keylen, - const unsigned char *IV, unsigned long IVlen, - const unsigned char *adata, unsigned long adatalen, - unsigned char *pt, unsigned long ptlen, - unsigned char *ct, - unsigned char *tag, unsigned long *taglen, - int direction); - - /** Accelerated one shot LTC_OMAC - @param key The secret key - @param keylen The key length (octets) - @param in The message - @param inlen Length of message (octets) - @param out [out] Destination for tag - @param outlen [in/out] Initial and final size of out - @return CRYPT_OK on success - */ - int (*omac_memory)( - const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); - - /** Accelerated one shot XCBC - @param key The secret key - @param keylen The key length (octets) - @param in The message - @param inlen Length of message (octets) - @param out [out] Destination for tag - @param outlen [in/out] Initial and final size of out - @return CRYPT_OK on success - */ - int (*xcbc_memory)( - const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); - - /** Accelerated one shot F9 - @param key The secret key - @param keylen The key length (octets) - @param in The message - @param inlen Length of message (octets) - @param out [out] Destination for tag - @param outlen [in/out] Initial and final size of out - @return CRYPT_OK on success - @remark Requires manual padding - */ - int (*f9_memory)( - const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); -} cipher_descriptor[]; - -#ifdef LTC_BLOWFISH -int blowfish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int blowfish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int blowfish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int blowfish_test(void); -void blowfish_done(symmetric_key *skey); -int blowfish_keysize(int *keysize); -extern const struct ltc_cipher_descriptor blowfish_desc; -#endif - -#ifdef LTC_RC5 -int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int rc5_test(void); -void rc5_done(symmetric_key *skey); -int rc5_keysize(int *keysize); -extern const struct ltc_cipher_descriptor rc5_desc; -#endif - -#ifdef LTC_RC6 -int rc6_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int rc6_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int rc6_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int rc6_test(void); -void rc6_done(symmetric_key *skey); -int rc6_keysize(int *keysize); -extern const struct ltc_cipher_descriptor rc6_desc; -#endif - -#ifdef LTC_RC2 -int rc2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int rc2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int rc2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int rc2_test(void); -void rc2_done(symmetric_key *skey); -int rc2_keysize(int *keysize); -extern const struct ltc_cipher_descriptor rc2_desc; -#endif - -#ifdef LTC_SAFERP -int saferp_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int saferp_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int saferp_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int saferp_test(void); -void saferp_done(symmetric_key *skey); -int saferp_keysize(int *keysize); -extern const struct ltc_cipher_descriptor saferp_desc; -#endif - -#ifdef LTC_SAFER -int safer_k64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int safer_sk64_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int safer_k128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int safer_sk128_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int safer_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *key); -int safer_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *key); -int safer_k64_test(void); -int safer_sk64_test(void); -int safer_sk128_test(void); -void safer_done(symmetric_key *skey); -int safer_64_keysize(int *keysize); -int safer_128_keysize(int *keysize); -extern const struct ltc_cipher_descriptor safer_k64_desc, safer_k128_desc, safer_sk64_desc, safer_sk128_desc; -#endif - -#ifdef LTC_RIJNDAEL - -/* make aes an alias */ -#define aes_setup rijndael_setup -#define aes_ecb_encrypt rijndael_ecb_encrypt -#define aes_ecb_decrypt rijndael_ecb_decrypt -#define aes_test rijndael_test -#define aes_done rijndael_done -#define aes_keysize rijndael_keysize - -#define aes_enc_setup rijndael_enc_setup -#define aes_enc_ecb_encrypt rijndael_enc_ecb_encrypt -#define aes_enc_keysize rijndael_enc_keysize - -int rijndael_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int rijndael_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int rijndael_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int rijndael_test(void); -void rijndael_done(symmetric_key *skey); -int rijndael_keysize(int *keysize); -int rijndael_enc_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int rijndael_enc_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -void rijndael_enc_done(symmetric_key *skey); -int rijndael_enc_keysize(int *keysize); -extern const struct ltc_cipher_descriptor rijndael_desc, aes_desc; -extern const struct ltc_cipher_descriptor rijndael_enc_desc, aes_enc_desc; -#endif - -#ifdef LTC_XTEA -int xtea_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int xtea_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int xtea_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int xtea_test(void); -void xtea_done(symmetric_key *skey); -int xtea_keysize(int *keysize); -extern const struct ltc_cipher_descriptor xtea_desc; -#endif - -#ifdef LTC_TWOFISH -int twofish_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int twofish_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int twofish_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int twofish_test(void); -void twofish_done(symmetric_key *skey); -int twofish_keysize(int *keysize); -extern const struct ltc_cipher_descriptor twofish_desc; -#endif - -#ifdef LTC_DES -int des_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int des_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int des_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int des_test(void); -void des_done(symmetric_key *skey); -int des_keysize(int *keysize); -extern const struct ltc_cipher_descriptor des_desc; -#ifdef LTC_DES3 -int des3_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int des3_test(void); -void des3_done(symmetric_key *skey); -int des3_keysize(int *keysize); -extern const struct ltc_cipher_descriptor des3_desc; -#endif -#endif - -#ifdef LTC_CAST5 -int cast5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int cast5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int cast5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int cast5_test(void); -void cast5_done(symmetric_key *skey); -int cast5_keysize(int *keysize); -extern const struct ltc_cipher_descriptor cast5_desc; -#endif - -#ifdef LTC_NOEKEON -int noekeon_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int noekeon_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int noekeon_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int noekeon_test(void); -void noekeon_done(symmetric_key *skey); -int noekeon_keysize(int *keysize); -extern const struct ltc_cipher_descriptor noekeon_desc; -#endif - -#ifdef LTC_SKIPJACK -int skipjack_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int skipjack_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int skipjack_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int skipjack_test(void); -void skipjack_done(symmetric_key *skey); -int skipjack_keysize(int *keysize); -extern const struct ltc_cipher_descriptor skipjack_desc; -#endif - -#ifdef LTC_KHAZAD -int khazad_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int khazad_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int khazad_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int khazad_test(void); -void khazad_done(symmetric_key *skey); -int khazad_keysize(int *keysize); -extern const struct ltc_cipher_descriptor khazad_desc; -#endif - -#ifdef LTC_ANUBIS -int anubis_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int anubis_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int anubis_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int anubis_test(void); -void anubis_done(symmetric_key *skey); -int anubis_keysize(int *keysize); -extern const struct ltc_cipher_descriptor anubis_desc; -#endif - -#ifdef LTC_KSEED -int kseed_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int kseed_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int kseed_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int kseed_test(void); -void kseed_done(symmetric_key *skey); -int kseed_keysize(int *keysize); -extern const struct ltc_cipher_descriptor kseed_desc; -#endif - -#ifdef LTC_KASUMI -int kasumi_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int kasumi_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int kasumi_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int kasumi_test(void); -void kasumi_done(symmetric_key *skey); -int kasumi_keysize(int *keysize); -extern const struct ltc_cipher_descriptor kasumi_desc; -#endif - - -#ifdef LTC_MULTI2 -int multi2_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey); -int multi2_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey); -int multi2_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey); -int multi2_test(void); -void multi2_done(symmetric_key *skey); -int multi2_keysize(int *keysize); -extern const struct ltc_cipher_descriptor multi2_desc; -#endif - -#ifdef LTC_ECB_MODE -int ecb_start(int cipher, const unsigned char *key, - int keylen, int num_rounds, symmetric_ECB *ecb); -int ecb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_ECB *ecb); -int ecb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_ECB *ecb); -int ecb_done(symmetric_ECB *ecb); -#endif - -#ifdef LTC_CFB_MODE -int cfb_start(int cipher, const unsigned char *IV, const unsigned char *key, - int keylen, int num_rounds, symmetric_CFB *cfb); -int cfb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CFB *cfb); -int cfb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CFB *cfb); -int cfb_getiv(unsigned char *IV, unsigned long *len, symmetric_CFB *cfb); -int cfb_setiv(const unsigned char *IV, unsigned long len, symmetric_CFB *cfb); -int cfb_done(symmetric_CFB *cfb); -#endif - -#ifdef LTC_OFB_MODE -int ofb_start(int cipher, const unsigned char *IV, const unsigned char *key, - int keylen, int num_rounds, symmetric_OFB *ofb); -int ofb_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_OFB *ofb); -int ofb_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_OFB *ofb); -int ofb_getiv(unsigned char *IV, unsigned long *len, symmetric_OFB *ofb); -int ofb_setiv(const unsigned char *IV, unsigned long len, symmetric_OFB *ofb); -int ofb_done(symmetric_OFB *ofb); -#endif - -#ifdef LTC_CBC_MODE -int cbc_start(int cipher, const unsigned char *IV, const unsigned char *key, - int keylen, int num_rounds, symmetric_CBC *cbc); -int cbc_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CBC *cbc); -int cbc_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CBC *cbc); -int cbc_getiv(unsigned char *IV, unsigned long *len, symmetric_CBC *cbc); -int cbc_setiv(const unsigned char *IV, unsigned long len, symmetric_CBC *cbc); -int cbc_done(symmetric_CBC *cbc); -#endif - -#ifdef LTC_CTR_MODE - -#define CTR_COUNTER_LITTLE_ENDIAN 0x0000 -#define CTR_COUNTER_BIG_ENDIAN 0x1000 -#define LTC_CTR_RFC3686 0x2000 - -int ctr_start( int cipher, - const unsigned char *IV, - const unsigned char *key, int keylen, - int num_rounds, int ctr_mode, - symmetric_CTR *ctr); -int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr); -int ctr_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_CTR *ctr); -int ctr_getiv(unsigned char *IV, unsigned long *len, symmetric_CTR *ctr); -int ctr_setiv(const unsigned char *IV, unsigned long len, symmetric_CTR *ctr); -int ctr_done(symmetric_CTR *ctr); -int ctr_test(void); -#endif - -#ifdef LTC_LRW_MODE - -#define LRW_ENCRYPT 0 -#define LRW_DECRYPT 1 - -int lrw_start( int cipher, - const unsigned char *IV, - const unsigned char *key, int keylen, - const unsigned char *tweak, - int num_rounds, - symmetric_LRW *lrw); -int lrw_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_LRW *lrw); -int lrw_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_LRW *lrw); -int lrw_getiv(unsigned char *IV, unsigned long *len, symmetric_LRW *lrw); -int lrw_setiv(const unsigned char *IV, unsigned long len, symmetric_LRW *lrw); -int lrw_done(symmetric_LRW *lrw); -int lrw_test(void); - -/* don't call */ -int lrw_process(const unsigned char *pt, unsigned char *ct, unsigned long len, int mode, symmetric_LRW *lrw); -#endif - -#ifdef LTC_F8_MODE -int f8_start( int cipher, const unsigned char *IV, - const unsigned char *key, int keylen, - const unsigned char *salt_key, int skeylen, - int num_rounds, symmetric_F8 *f8); -int f8_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_F8 *f8); -int f8_decrypt(const unsigned char *ct, unsigned char *pt, unsigned long len, symmetric_F8 *f8); -int f8_getiv(unsigned char *IV, unsigned long *len, symmetric_F8 *f8); -int f8_setiv(const unsigned char *IV, unsigned long len, symmetric_F8 *f8); -int f8_done(symmetric_F8 *f8); -int f8_test_mode(void); -#endif - -#ifdef LTC_XTS_MODE -typedef struct { - symmetric_key key1, key2; - int cipher; -} symmetric_xts; - -int xts_start( int cipher, - const unsigned char *key1, - const unsigned char *key2, - unsigned long keylen, - int num_rounds, - symmetric_xts *xts); - -int xts_encrypt( - const unsigned char *pt, unsigned long ptlen, - unsigned char *ct, - const unsigned char *tweak, - symmetric_xts *xts); -int xts_decrypt( - const unsigned char *ct, unsigned long ptlen, - unsigned char *pt, - const unsigned char *tweak, - symmetric_xts *xts); - -void xts_done(symmetric_xts *xts); -int xts_test(void); -void xts_mult_x(unsigned char *I); -#endif - -int find_cipher(const char *name); -int find_cipher_any(const char *name, int blocklen, int keylen); -int find_cipher_id(unsigned char ID); -int register_cipher(const struct ltc_cipher_descriptor *cipher); -int unregister_cipher(const struct ltc_cipher_descriptor *cipher); -int cipher_is_valid(int idx); - -LTC_MUTEX_PROTO(ltc_cipher_mutex) - -/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_cipher.h,v $ */ -/* $Revision: 1.54 $ */ -/* $Date: 2007/05/12 14:37:41 $ */ diff --git a/crypto/tomcrypt_custom.h b/crypto/tomcrypt_custom.h deleted file mode 100644 index 2eb51545..00000000 --- a/crypto/tomcrypt_custom.h +++ /dev/null @@ -1,425 +0,0 @@ -#ifndef TOMCRYPT_CUSTOM_H_ -#define TOMCRYPT_CUSTOM_H_ - -#define ARGTYPE 1 -#define LTC_SMALL_CODE -#define LTC_NO_ASM -#define LTC_NO_CIPHERS -#define LTC_NO_MODES -#define LTC_NO_HASHES -#define LTC_NO_MACS -#define LTC_NO_PRNGS -#define LTC_NO_PK -#define LTC_NO_PKCS -#define LTC_NO_TEST -#define LTC_MD4 -#define LTC_MD5 -#define LTC_SHA1 -#define LTC_DES -#undef LTC_DES3 - -/* macros for various libc functions you can change for embedded targets */ -#ifndef XMALLOC - #ifdef malloc - #define LTC_NO_PROTOTYPES - #endif -#define XMALLOC malloc -#endif -#ifndef XREALLOC - #ifdef realloc - #define LTC_NO_PROTOTYPES - #endif -#define XREALLOC realloc -#endif -#ifndef XCALLOC - #ifdef calloc - #define LTC_NO_PROTOTYPES - #endif -#define XCALLOC calloc -#endif -#ifndef XFREE - #ifdef free - #define LTC_NO_PROTOTYPES - #endif -#define XFREE free -#endif - -#ifndef XMEMSET - #ifdef memset - #define LTC_NO_PROTOTYPES - #endif -#define XMEMSET memset -#endif -#ifndef XMEMCPY - #ifdef memcpy - #define LTC_NO_PROTOTYPES - #endif -#define XMEMCPY memcpy -#endif -#ifndef XMEMCMP - #ifdef memcmp - #define LTC_NO_PROTOTYPES - #endif -#define XMEMCMP memcmp -#endif -#ifndef XSTRCMP - #ifdef strcmp - #define LTC_NO_PROTOTYPES - #endif -#define XSTRCMP strcmp -#endif - -#ifndef XCLOCK -#define XCLOCK clock -#endif -#ifndef XCLOCKS_PER_SEC -#define XCLOCKS_PER_SEC CLOCKS_PER_SEC -#endif - -#ifndef XQSORT - #ifdef qsort - #define LTC_NO_PROTOTYPES - #endif -#define XQSORT qsort -#endif - -/* Easy button? */ -#ifdef LTC_EASY - #define LTC_NO_CIPHERS - #define LTC_RIJNDAEL - #define LTC_BLOWFISH - #define LTC_DES - #define LTC_DES3 - #define LTC_CAST5 - - #define LTC_NO_MODES - #define LTC_ECB_MODE - #define LTC_CBC_MODE - #define LTC_CTR_MODE - - #define LTC_NO_HASHES - #define LTC_SHA1 - #define LTC_SHA512 - #define LTC_SHA384 - #define LTC_SHA256 - #define LTC_SHA224 - - #define LTC_NO_MACS - #define LTC_HMAC - #define LTC_OMAC - #define LTC_CCM_MODE - - #define LTC_NO_PRNGS - #define LTC_SPRNG - #define LTC_YARROW - #define LTC_DEVRANDOM - #define TRY_URANDOM_FIRST - - #define LTC_NO_PK - #define LTC_MRSA - #define LTC_MECC -#endif - -/* Use small code where possible */ -/* #define LTC_SMALL_CODE */ - -/* Enable self-test test vector checking */ -#ifndef LTC_NO_TEST - #define LTC_TEST -#endif - -/* clean the stack of functions which put private information on stack */ -/* #define LTC_CLEAN_STACK */ - -/* disable all file related functions */ -/* #define LTC_NO_FILE */ - -/* disable all forms of ASM */ -/* #define LTC_NO_ASM */ - -/* disable FAST mode */ -/* #define LTC_NO_FAST */ - -/* disable BSWAP on x86 */ -/* #define LTC_NO_BSWAP */ - -/* ---> Symmetric Block Ciphers <--- */ -#ifndef LTC_NO_CIPHERS - -#define LTC_BLOWFISH -#define LTC_RC2 -#define LTC_RC5 -#define LTC_RC6 -#define LTC_SAFERP -#define LTC_RIJNDAEL -#define LTC_XTEA -/* _TABLES tells it to use tables during setup, _SMALL means to use the smaller scheduled key format - * (saves 4KB of ram), _ALL_TABLES enables all tables during setup */ -#define LTC_TWOFISH -#ifndef LTC_NO_TABLES - #define LTC_TWOFISH_TABLES - /* #define LTC_TWOFISH_ALL_TABLES */ -#else - #define LTC_TWOFISH_SMALL -#endif -/* #define LTC_TWOFISH_SMALL */ -/* LTC_DES includes EDE triple-LTC_DES */ -#define LTC_DES -#define LTC_DES3 -#define LTC_CAST5 -#define LTC_NOEKEON -#define LTC_SKIPJACK -#define LTC_SAFER -#define LTC_KHAZAD -#define LTC_ANUBIS -#define LTC_ANUBIS_TWEAK -#define LTC_KSEED -#define LTC_KASUMI - -#endif /* LTC_NO_CIPHERS */ - - -/* ---> Block Cipher Modes of Operation <--- */ -#ifndef LTC_NO_MODES - -#define LTC_CFB_MODE -#define LTC_OFB_MODE -#define LTC_ECB_MODE -#define LTC_CBC_MODE -#define LTC_CTR_MODE - -/* F8 chaining mode */ -#define LTC_F8_MODE - -/* LRW mode */ -#define LTC_LRW_MODE -#ifndef LTC_NO_TABLES - /* like GCM mode this will enable 16 8x128 tables [64KB] that make - * seeking very fast. - */ - #define LRW_TABLES -#endif - -/* XTS mode */ -#define LTC_XTS_MODE - -#endif /* LTC_NO_MODES */ - -/* ---> One-Way Hash Functions <--- */ -#ifndef LTC_NO_HASHES - -#define LTC_CHC_HASH -#define LTC_WHIRLPOOL -#define LTC_SHA512 -#define LTC_SHA384 -#define LTC_SHA256 -#define LTC_SHA224 -#define LTC_TIGER -#define LTC_SHA1 -#define LTC_MD5 -#define LTC_MD4 -#define LTC_MD2 -#define LTC_RIPEMD128 -#define LTC_RIPEMD160 -#define LTC_RIPEMD256 -#define LTC_RIPEMD320 - -#endif /* LTC_NO_HASHES */ - -/* ---> MAC functions <--- */ -#ifndef LTC_NO_MACS - -#define LTC_HMAC -#define LTC_OMAC -#define LTC_PMAC -#define LTC_XCBC -#define LTC_F9_MODE -#define LTC_PELICAN - -#if defined(LTC_PELICAN) && !defined(LTC_RIJNDAEL) - #error Pelican-MAC requires LTC_RIJNDAEL -#endif - -/* ---> Encrypt + Authenticate Modes <--- */ - -#define LTC_EAX_MODE -#if defined(LTC_EAX_MODE) && !(defined(LTC_CTR_MODE) && defined(LTC_OMAC)) - #error LTC_EAX_MODE requires CTR and LTC_OMAC mode -#endif - -#define LTC_OCB_MODE -#define LTC_CCM_MODE -#define LTC_GCM_MODE - -/* Use 64KiB tables */ -#ifndef LTC_NO_TABLES - #define LTC_GCM_TABLES -#endif - -/* USE SSE2? requires GCC works on x86_32 and x86_64*/ -#ifdef LTC_GCM_TABLES -/* #define LTC_GCM_TABLES_SSE2 */ -#endif - -#endif /* LTC_NO_MACS */ - -/* Various tidbits of modern neatoness */ -#define LTC_BASE64 - -/* --> Pseudo Random Number Generators <--- */ -#ifndef LTC_NO_PRNGS - -/* Yarrow */ -#define LTC_YARROW -/* which descriptor of AES to use? */ -/* 0 = rijndael_enc 1 = aes_enc, 2 = rijndael [full], 3 = aes [full] */ -#define LTC_YARROW_AES 0 - -#if defined(LTC_YARROW) && !defined(LTC_CTR_MODE) - #error LTC_YARROW requires LTC_CTR_MODE chaining mode to be defined! -#endif - -/* a PRNG that simply reads from an available system source */ -#define LTC_SPRNG - -/* The LTC_RC4 stream cipher */ -#define LTC_RC4 - -/* Fortuna PRNG */ -#define LTC_FORTUNA -/* reseed every N calls to the read function */ -#define LTC_FORTUNA_WD 10 -/* number of pools (4..32) can save a bit of ram by lowering the count */ -#define LTC_FORTUNA_POOLS 32 - -/* Greg's LTC_SOBER128 PRNG ;-0 */ -#define LTC_SOBER128 - -/* the *nix style /dev/random device */ -#define LTC_DEVRANDOM -/* try /dev/urandom before trying /dev/random */ -#define TRY_URANDOM_FIRST - -#endif /* LTC_NO_PRNGS */ - -/* ---> math provider? <--- */ -#ifndef LTC_NO_MATH - -/* LibTomMath */ -/* #define LTM_LTC_DESC */ - -/* TomsFastMath */ -/* #define TFM_LTC_DESC */ - -#endif /* LTC_NO_MATH */ - -/* ---> Public Key Crypto <--- */ -#ifndef LTC_NO_PK - -/* Include RSA support */ -#define LTC_MRSA - -/* Include Katja (a Rabin variant like RSA) */ -/* #define MKAT */ - -/* Digital Signature Algorithm */ -#define LTC_MDSA - -/* ECC */ -#define LTC_MECC - -/* use Shamir's trick for point mul (speeds up signature verification) */ -#define LTC_ECC_SHAMIR - -#if defined(TFM_LTC_DESC) && defined(LTC_MECC) - #define LTC_MECC_ACCEL -#endif - -/* do we want fixed point ECC */ -/* #define LTC_MECC_FP */ - -/* Timing Resistant? */ -/* #define LTC_ECC_TIMING_RESISTANT */ - -#endif /* LTC_NO_PK */ - -/* LTC_PKCS #1 (RSA) and #5 (Password Handling) stuff */ -#ifndef LTC_NO_PKCS - -#define LTC_PKCS_1 -#define LTC_PKCS_5 - -/* Include ASN.1 DER (required by DSA/RSA) */ -#define LTC_DER - -#endif /* LTC_NO_PKCS */ - -/* cleanup */ - -#ifdef LTC_MECC -/* Supported ECC Key Sizes */ -#ifndef LTC_NO_CURVES - #define ECC112 - #define ECC128 - #define ECC160 - #define ECC192 - #define ECC224 - #define ECC256 - #define ECC384 - #define ECC521 -#endif -#endif - -#if defined(LTC_MECC) || defined(LTC_MRSA) || defined(LTC_MDSA) || defined(MKATJA) - /* Include the MPI functionality? (required by the PK algorithms) */ - #define MPI -#endif - -#ifdef LTC_MRSA - #define LTC_PKCS_1 -#endif - -#if defined(LTC_DER) && !defined(MPI) - #error ASN.1 DER requires MPI functionality -#endif - -#if (defined(LTC_MDSA) || defined(LTC_MRSA) || defined(LTC_MECC) || defined(MKATJA)) && !defined(LTC_DER) - #error PK requires ASN.1 DER functionality, make sure LTC_DER is enabled -#endif - -/* THREAD management */ -#ifdef LTC_PTHREAD - -#include <pthread.h> - -#define LTC_MUTEX_GLOBAL(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; -#define LTC_MUTEX_PROTO(x) extern pthread_mutex_t x; -#define LTC_MUTEX_TYPE(x) pthread_mutex_t x; -#define LTC_MUTEX_INIT(x) pthread_mutex_init(x, NULL); -#define LTC_MUTEX_LOCK(x) pthread_mutex_lock(x); -#define LTC_MUTEX_UNLOCK(x) pthread_mutex_unlock(x); - -#else - -/* default no functions */ -#define LTC_MUTEX_GLOBAL(x) -#define LTC_MUTEX_PROTO(x) -#define LTC_MUTEX_TYPE(x) -#define LTC_MUTEX_INIT(x) -#define LTC_MUTEX_LOCK(x) -#define LTC_MUTEX_UNLOCK(x) - -#endif - -/* Debuggers */ - -/* define this if you use Valgrind, note: it CHANGES the way SOBER-128 and LTC_RC4 work (see the code) */ -/* #define LTC_VALGRIND */ - -#endif - - - -/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_custom.h,v $ */ -/* $Revision: 1.73 $ */ -/* $Date: 2007/05/12 14:37:41 $ */ diff --git a/crypto/tomcrypt_hash.h b/crypto/tomcrypt_hash.h deleted file mode 100644 index c3a3179e..00000000 --- a/crypto/tomcrypt_hash.h +++ /dev/null @@ -1,379 +0,0 @@ -/* ---- HASH FUNCTIONS ---- */ -#ifdef LTC_SHA512 -struct sha512_state { - ulong64 length, state[8]; - unsigned long curlen; - unsigned char buf[128]; -}; -#endif - -#ifdef LTC_SHA256 -struct sha256_state { - ulong64 length; - ulong32 state[8], curlen; - unsigned char buf[64]; -}; -#endif - -#ifdef LTC_SHA1 -struct sha1_state { - ulong64 length; - ulong32 state[5], curlen; - unsigned char buf[64]; -}; -#endif - -#ifdef LTC_MD5 -struct md5_state { - ulong64 length; - ulong32 state[4], curlen; - unsigned char buf[64]; -}; -#endif - -#ifdef LTC_MD4 -struct md4_state { - ulong64 length; - ulong32 state[4], curlen; - unsigned char buf[64]; -}; -#endif - -#ifdef LTC_TIGER -struct tiger_state { - ulong64 state[3], length; - unsigned long curlen; - unsigned char buf[64]; -}; -#endif - -#ifdef LTC_MD2 -struct md2_state { - unsigned char chksum[16], X[48], buf[16]; - unsigned long curlen; -}; -#endif - -#ifdef LTC_RIPEMD128 -struct rmd128_state { - ulong64 length; - unsigned char buf[64]; - ulong32 curlen, state[4]; -}; -#endif - -#ifdef LTC_RIPEMD160 -struct rmd160_state { - ulong64 length; - unsigned char buf[64]; - ulong32 curlen, state[5]; -}; -#endif - -#ifdef LTC_RIPEMD256 -struct rmd256_state { - ulong64 length; - unsigned char buf[64]; - ulong32 curlen, state[8]; -}; -#endif - -#ifdef LTC_RIPEMD320 -struct rmd320_state { - ulong64 length; - unsigned char buf[64]; - ulong32 curlen, state[10]; -}; -#endif - -#ifdef LTC_WHIRLPOOL -struct whirlpool_state { - ulong64 length, state[8]; - unsigned char buf[64]; - ulong32 curlen; -}; -#endif - -#ifdef LTC_CHC_HASH -struct chc_state { - ulong64 length; - unsigned char state[MAXBLOCKSIZE], buf[MAXBLOCKSIZE]; - ulong32 curlen; -}; -#endif - -typedef union Hash_state { - char dummy[1]; -#ifdef LTC_CHC_HASH - struct chc_state chc; -#endif -#ifdef LTC_WHIRLPOOL - struct whirlpool_state whirlpool; -#endif -#ifdef LTC_SHA512 - struct sha512_state sha512; -#endif -#ifdef LTC_SHA256 - struct sha256_state sha256; -#endif -#ifdef LTC_SHA1 - struct sha1_state sha1; -#endif -#ifdef LTC_MD5 - struct md5_state md5; -#endif -#ifdef LTC_MD4 - struct md4_state md4; -#endif -#ifdef LTC_MD2 - struct md2_state md2; -#endif -#ifdef LTC_TIGER - struct tiger_state tiger; -#endif -#ifdef LTC_RIPEMD128 - struct rmd128_state rmd128; -#endif -#ifdef LTC_RIPEMD160 - struct rmd160_state rmd160; -#endif -#ifdef LTC_RIPEMD256 - struct rmd256_state rmd256; -#endif -#ifdef LTC_RIPEMD320 - struct rmd320_state rmd320; -#endif - void *data; -} hash_state; - -/** hash descriptor */ -extern struct ltc_hash_descriptor { - /** name of hash */ - char *name; - /** internal ID */ - unsigned char ID; - /** Size of digest in octets */ - unsigned long hashsize; - /** Input block size in octets */ - unsigned long blocksize; - /** ASN.1 OID */ - unsigned long OID[16]; - /** Length of DER encoding */ - unsigned long OIDlen; - - /** Init a hash state - @param hash The hash to initialize - @return CRYPT_OK if successful - */ - int (*init)(hash_state *hash); - /** Process a block of data - @param hash The hash state - @param in The data to hash - @param inlen The length of the data (octets) - @return CRYPT_OK if successful - */ - int (*process)(hash_state *hash, const unsigned char *in, unsigned long inlen); - /** Produce the digest and store it - @param hash The hash state - @param out [out] The destination of the digest - @return CRYPT_OK if successful - */ - int (*done)(hash_state *hash, unsigned char *out); - /** Self-test - @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled - */ - int (*test)(void); - - /* accelerated hmac callback: if you need to-do multiple packets just use the generic hmac_memory and provide a hash callback */ - int (*hmac_block)(const unsigned char *key, unsigned long keylen, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); - -} hash_descriptor[]; - -#ifdef LTC_CHC_HASH -int chc_register(int cipher); -int chc_init(hash_state * md); -int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int chc_done(hash_state * md, unsigned char *hash); -int chc_test(void); -extern const struct ltc_hash_descriptor chc_desc; -#endif - -#ifdef LTC_WHIRLPOOL -int whirlpool_init(hash_state * md); -int whirlpool_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int whirlpool_done(hash_state * md, unsigned char *hash); -int whirlpool_test(void); -extern const struct ltc_hash_descriptor whirlpool_desc; -#endif - -#ifdef LTC_SHA512 -int sha512_init(hash_state * md); -int sha512_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int sha512_done(hash_state * md, unsigned char *hash); -int sha512_test(void); -extern const struct ltc_hash_descriptor sha512_desc; -#endif - -#ifdef LTC_SHA384 -#ifndef LTC_SHA512 - #error LTC_SHA512 is required for LTC_SHA384 -#endif -int sha384_init(hash_state * md); -#define sha384_process sha512_process -int sha384_done(hash_state * md, unsigned char *hash); -int sha384_test(void); -extern const struct ltc_hash_descriptor sha384_desc; -#endif - -#ifdef LTC_SHA256 -int sha256_init(hash_state * md); -int sha256_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int sha256_done(hash_state * md, unsigned char *hash); -int sha256_test(void); -extern const struct ltc_hash_descriptor sha256_desc; - -#ifdef LTC_SHA224 -#ifndef LTC_SHA256 - #error LTC_SHA256 is required for LTC_SHA224 -#endif -int sha224_init(hash_state * md); -#define sha224_process sha256_process -int sha224_done(hash_state * md, unsigned char *hash); -int sha224_test(void); -extern const struct ltc_hash_descriptor sha224_desc; -#endif -#endif - -#ifdef LTC_SHA1 -int sha1_init(hash_state * md); -int sha1_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int sha1_done(hash_state * md, unsigned char *hash); -int sha1_test(void); -extern const struct ltc_hash_descriptor sha1_desc; -#endif - -#ifdef LTC_MD5 -int md5_init(hash_state * md); -int md5_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int md5_done(hash_state * md, unsigned char *hash); -int md5_test(void); -extern const struct ltc_hash_descriptor md5_desc; -#endif - -#ifdef LTC_MD4 -int md4_init(hash_state * md); -int md4_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int md4_done(hash_state * md, unsigned char *hash); -int md4_test(void); -extern const struct ltc_hash_descriptor md4_desc; -#endif - -#ifdef LTC_MD2 -int md2_init(hash_state * md); -int md2_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int md2_done(hash_state * md, unsigned char *hash); -int md2_test(void); -extern const struct ltc_hash_descriptor md2_desc; -#endif - -#ifdef LTC_TIGER -int tiger_init(hash_state * md); -int tiger_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int tiger_done(hash_state * md, unsigned char *hash); -int tiger_test(void); -extern const struct ltc_hash_descriptor tiger_desc; -#endif - -#ifdef LTC_RIPEMD128 -int rmd128_init(hash_state * md); -int rmd128_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int rmd128_done(hash_state * md, unsigned char *hash); -int rmd128_test(void); -extern const struct ltc_hash_descriptor rmd128_desc; -#endif - -#ifdef LTC_RIPEMD160 -int rmd160_init(hash_state * md); -int rmd160_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int rmd160_done(hash_state * md, unsigned char *hash); -int rmd160_test(void); -extern const struct ltc_hash_descriptor rmd160_desc; -#endif - -#ifdef LTC_RIPEMD256 -int rmd256_init(hash_state * md); -int rmd256_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int rmd256_done(hash_state * md, unsigned char *hash); -int rmd256_test(void); -extern const struct ltc_hash_descriptor rmd256_desc; -#endif - -#ifdef LTC_RIPEMD320 -int rmd320_init(hash_state * md); -int rmd320_process(hash_state * md, const unsigned char *in, unsigned long inlen); -int rmd320_done(hash_state * md, unsigned char *hash); -int rmd320_test(void); -extern const struct ltc_hash_descriptor rmd320_desc; -#endif - - -int find_hash(const char *name); -int find_hash_id(unsigned char ID); -int find_hash_oid(const unsigned long *ID, unsigned long IDlen); -int find_hash_any(const char *name, int digestlen); -int register_hash(const struct ltc_hash_descriptor *hash); -int unregister_hash(const struct ltc_hash_descriptor *hash); -int hash_is_valid(int idx); - -LTC_MUTEX_PROTO(ltc_hash_mutex) - -int hash_memory(int hash, - const unsigned char *in, unsigned long inlen, - unsigned char *out, unsigned long *outlen); -int hash_memory_multi(int hash, unsigned char *out, unsigned long *outlen, - const unsigned char *in, unsigned long inlen, ...); -int hash_filehandle(int hash, FILE *in, unsigned char *out, unsigned long *outlen); -int hash_file(int hash, const char *fname, unsigned char *out, unsigned long *outlen); - -/* a simple macro for making hash "process" functions */ -#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \ -int func_name (hash_state * md, const unsigned char *in, unsigned long inlen) \ -{ \ - unsigned long n; \ - int err; \ - LTC_ARGCHK(md != NULL); \ - LTC_ARGCHK(in != NULL); \ - if (md-> state_var .curlen > sizeof(md-> state_var .buf)) { \ - return CRYPT_INVALID_ARG; \ - } \ - while (inlen > 0) { \ - if (md-> state_var .curlen == 0 && inlen >= block_size) { \ - if ((err = compress_name (md, (unsigned char *)in)) != CRYPT_OK) { \ - return err; \ - } \ - md-> state_var .length += block_size * 8; \ - in += block_size; \ - inlen -= block_size; \ - } else { \ - n = MIN(inlen, (block_size - md-> state_var .curlen)); \ - memcpy(md-> state_var .buf + md-> state_var.curlen, in, (size_t)n); \ - md-> state_var .curlen += n; \ - in += n; \ - inlen -= n; \ - if (md-> state_var .curlen == block_size) { \ - if ((err = compress_name (md, md-> state_var .buf)) != CRYPT_OK) { \ - return err; \ - } \ - md-> state_var .length += 8*block_size; \ - md-> state_var .curlen = 0; \ - } \ - } \ - } \ - return CRYPT_OK; \ -} - -/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_hash.h,v $ */ -/* $Revision: 1.22 $ */ -/* $Date: 2007/05/12 14:32:35 $ */ diff --git a/crypto/tomcrypt_macros.h b/crypto/tomcrypt_macros.h deleted file mode 100644 index 94c9148e..00000000 --- a/crypto/tomcrypt_macros.h +++ /dev/null @@ -1,424 +0,0 @@ -/* fix for MSVC ...evil! */ -#ifdef _MSC_VER - #define CONST64(n) n ## ui64 - typedef unsigned __int64 ulong64; -#else - #define CONST64(n) n ## ULL - typedef unsigned long long ulong64; -#endif - -/* this is the "32-bit at least" data type - * Re-define it to suit your platform but it must be at least 32-bits - */ -#if defined(__x86_64__) || (defined(__sparc__) && defined(__arch64__)) - typedef unsigned ulong32; -#else - typedef unsigned long ulong32; -#endif - -/* ---- HELPER MACROS ---- */ -#ifdef ENDIAN_NEUTRAL - -#define STORE32L(x, y) \ - { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ - (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } - -#define LOAD32L(x, y) \ - { x = ((unsigned long)((y)[3] & 255)<<24) | \ - ((unsigned long)((y)[2] & 255)<<16) | \ - ((unsigned long)((y)[1] & 255)<<8) | \ - ((unsigned long)((y)[0] & 255)); } - -#define STORE64L(x, y) \ - { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ - (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ - (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ - (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } - -#define LOAD64L(x, y) \ - { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \ - (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \ - (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \ - (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } - -#define STORE32H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ - (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } - -#define LOAD32H(x, y) \ - { x = ((unsigned long)((y)[0] & 255)<<24) | \ - ((unsigned long)((y)[1] & 255)<<16) | \ - ((unsigned long)((y)[2] & 255)<<8) | \ - ((unsigned long)((y)[3] & 255)); } - -#define STORE64H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ - (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ - (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ - (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } - -#define LOAD64H(x, y) \ - { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \ - (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \ - (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \ - (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } - -#endif /* ENDIAN_NEUTRAL */ - -#ifdef ENDIAN_LITTLE - -#if !defined(LTC_NO_BSWAP) && (defined(INTEL_CC) || (defined(__GNUC__) && (defined(__DJGPP__) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__i386__) || defined(__x86_64__)))) - -#define STORE32H(x, y) \ -asm __volatile__ ( \ - "bswapl %0 \n\t" \ - "movl %0,(%1)\n\t" \ - "bswapl %0 \n\t" \ - ::"r"(x), "r"(y)); - -#define LOAD32H(x, y) \ -asm __volatile__ ( \ - "movl (%1),%0\n\t" \ - "bswapl %0\n\t" \ - :"=r"(x): "r"(y)); - -#else - -#define STORE32H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \ - (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); } - -#define LOAD32H(x, y) \ - { x = ((unsigned long)((y)[0] & 255)<<24) | \ - ((unsigned long)((y)[1] & 255)<<16) | \ - ((unsigned long)((y)[2] & 255)<<8) | \ - ((unsigned long)((y)[3] & 255)); } - -#endif - - -/* x86_64 processor */ -#if !defined(LTC_NO_BSWAP) && (defined(__GNUC__) && defined(__x86_64__)) - -#define STORE64H(x, y) \ -asm __volatile__ ( \ - "bswapq %0 \n\t" \ - "movq %0,(%1)\n\t" \ - "bswapq %0 \n\t" \ - ::"r"(x), "r"(y)); - -#define LOAD64H(x, y) \ -asm __volatile__ ( \ - "movq (%1),%0\n\t" \ - "bswapq %0\n\t" \ - :"=r"(x): "r"(y)); - -#else - -#define STORE64H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ - (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ - (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ - (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } - -#define LOAD64H(x, y) \ - { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \ - (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \ - (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \ - (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); } - -#endif - -#ifdef ENDIAN_32BITWORD - -#define STORE32L(x, y) \ - { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } - -#define LOAD32L(x, y) \ - XMEMCPY(&(x), y, 4); - -#define STORE64L(x, y) \ - { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ - (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ - (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ - (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } - -#define LOAD64L(x, y) \ - { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \ - (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \ - (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \ - (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } - -#else /* 64-bit words then */ - -#define STORE32L(x, y) \ - { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } - -#define LOAD32L(x, y) \ - { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; } - -#define STORE64L(x, y) \ - { ulong64 __t = (x); XMEMCPY(y, &__t, 8); } - -#define LOAD64L(x, y) \ - { XMEMCPY(&(x), y, 8); } - -#endif /* ENDIAN_64BITWORD */ - -#endif /* ENDIAN_LITTLE */ - -#ifdef ENDIAN_BIG -#define STORE32L(x, y) \ - { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ - (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } - -#define LOAD32L(x, y) \ - { x = ((unsigned long)((y)[3] & 255)<<24) | \ - ((unsigned long)((y)[2] & 255)<<16) | \ - ((unsigned long)((y)[1] & 255)<<8) | \ - ((unsigned long)((y)[0] & 255)); } - -#define STORE64L(x, y) \ - { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \ - (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \ - (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \ - (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); } - -#define LOAD64L(x, y) \ - { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \ - (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \ - (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \ - (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); } - -#ifdef ENDIAN_32BITWORD - -#define STORE32H(x, y) \ - { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } - -#define LOAD32H(x, y) \ - XMEMCPY(&(x), y, 4); - -#define STORE64H(x, y) \ - { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ - (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ - (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ - (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } - -#define LOAD64H(x, y) \ - { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \ - (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \ - (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \ - (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); } - -#else /* 64-bit words then */ - -#define STORE32H(x, y) \ - { ulong32 __t = (x); XMEMCPY(y, &__t, 4); } - -#define LOAD32H(x, y) \ - { XMEMCPY(&(x), y, 4); x &= 0xFFFFFFFF; } - -#define STORE64H(x, y) \ - { ulong64 __t = (x); XMEMCPY(y, &__t, 8); } - -#define LOAD64H(x, y) \ - { XMEMCPY(&(x), y, 8); } - -#endif /* ENDIAN_64BITWORD */ -#endif /* ENDIAN_BIG */ - -#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \ - ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) ) - - -/* 32-bit Rotates */ -#if defined(_MSC_VER) - -/* instrinsic rotate */ -#include <stdlib.h> -#pragma intrinsic(_lrotr,_lrotl) -#define ROR(x,n) _lrotr(x,n) -#define ROL(x,n) _lrotl(x,n) -#define RORc(x,n) _lrotr(x,n) -#define ROLc(x,n) _lrotl(x,n) - -#elif !defined(__STRICT_ANSI__) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(LTC_NO_ASM) - -static inline unsigned ROL(unsigned word, int i) -{ - asm ("roll %%cl,%0" - :"=r" (word) - :"0" (word),"c" (i)); - return word; -} - -static inline unsigned ROR(unsigned word, int i) -{ - asm ("rorl %%cl,%0" - :"=r" (word) - :"0" (word),"c" (i)); - return word; -} - -#ifndef LTC_NO_ROLC - -static inline unsigned ROLc(unsigned word, const int i) -{ - asm ("roll %2,%0" - :"=r" (word) - :"0" (word),"I" (i)); - return word; -} - -static inline unsigned RORc(unsigned word, const int i) -{ - asm ("rorl %2,%0" - :"=r" (word) - :"0" (word),"I" (i)); - return word; -} - -#else - -#define ROLc ROL -#define RORc ROR - -#endif - -#elif !defined(__STRICT_ANSI__) && defined(LTC_PPC32) - -static inline unsigned ROL(unsigned word, int i) -{ - asm ("rotlw %0,%0,%2" - :"=r" (word) - :"0" (word),"r" (i)); - return word; -} - -static inline unsigned ROR(unsigned word, int i) -{ - asm ("rotlw %0,%0,%2" - :"=r" (word) - :"0" (word),"r" (32-i)); - return word; -} - -#ifndef LTC_NO_ROLC - -static inline unsigned ROLc(unsigned word, const int i) -{ - asm ("rotlwi %0,%0,%2" - :"=r" (word) - :"0" (word),"I" (i)); - return word; -} - -static inline unsigned RORc(unsigned word, const int i) -{ - asm ("rotrwi %0,%0,%2" - :"=r" (word) - :"0" (word),"I" (i)); - return word; -} - -#else - -#define ROLc ROL -#define RORc ROR - -#endif - - -#else - -/* rotates the hard way */ -#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) -#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) -#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) -#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) - -#endif - - -/* 64-bit Rotates */ -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) && defined(__x86_64__) && !defined(LTC_NO_ASM) - -static inline unsigned long long ROL64(unsigned long long word, int i) -{ - asm("rolq %%cl,%0" - :"=r" (word) - :"0" (word),"c" (i)); - return word; -} - -static inline unsigned long long ROR64(unsigned long long word, int i) -{ - asm("rorq %%cl,%0" - :"=r" (word) - :"0" (word),"c" (i)); - return word; -} - -#ifndef LTC_NO_ROLC - -static inline unsigned long long ROL64c(unsigned long long word, const int i) -{ - asm("rolq %2,%0" - :"=r" (word) - :"0" (word),"J" (i)); - return word; -} - -static inline unsigned long long ROR64c(unsigned long long word, const int i) -{ - asm("rorq %2,%0" - :"=r" (word) - :"0" (word),"J" (i)); - return word; -} - -#else /* LTC_NO_ROLC */ - -#define ROL64c ROL64 -#define ROR64c ROR64 - -#endif - -#else /* Not x86_64 */ - -#define ROL64(x, y) \ - ( (((x)<<((ulong64)(y)&63)) | \ - (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF)) - -#define ROR64(x, y) \ - ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \ - ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF)) - -#define ROL64c(x, y) \ - ( (((x)<<((ulong64)(y)&63)) | \ - (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF)) - -#define ROR64c(x, y) \ - ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \ - ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF)) - -#endif - -#ifndef MAX - #define MAX(x, y) ( ((x)>(y))?(x):(y) ) -#endif - -#ifndef MIN - #define MIN(x, y) ( ((x)<(y))?(x):(y) ) -#endif - -/* extract a byte portably */ -#ifdef _MSC_VER - #define byte(x, n) ((unsigned char)((x) >> (8 * (n)))) -#else - #define byte(x, n) (((x) >> (8 * (n))) & 255) -#endif - -/* $Source: /cvs/libtom/libtomcrypt/src/headers/tomcrypt_macros.h,v $ */ -/* $Revision: 1.15 $ */ -/* $Date: 2006/11/29 23:43:57 $ */ diff --git a/docs/ipoe_radius.md b/docs/ipoe_radius.md new file mode 100644 index 00000000..9bd0aecb --- /dev/null +++ b/docs/ipoe_radius.md @@ -0,0 +1,98 @@ +# Supplying DHCP Options via RADIUS for IPoE Sessions + +accel-ppp supports dynamically providing various DHCP options to IPoE clients by configuring corresponding RADIUS attributes. This allows for flexible and centralized management of DHCP parameters delivered to clients. + +## Mechanism + +The `ipoe` module processes RADIUS Access-Accept packets to extract DHCP options that need to be delivered to the client. This is achieved by mapping specific RADIUS Vendor-Specific Attributes (VSAs) to DHCP options. Whether you're sending a standard DHCP option (like DNS servers) or the DHCP-specific "Vendor-Specific Information" option (Option 43), the mechanism uses this common VSA structure: + +* **RADIUS Vendor ID:** `54` + * This ID is internally designated by accel-ppp (and commonly in FreeRADIUS dictionaries) as the "DHCP" vendor. +* **RADIUS Attribute ID:** This directly corresponds to the **DHCP Option Code** you wish to send (e.g., `6` for DNS Servers, `43` for Vendor-Specific Information). +* **RADIUS Attribute Value:** This is the raw binary payload (octets) of the DHCP option. accel-ppp will encapsulate this value into the DHCP option's data field. + +When accel-ppp receives an Access-Accept packet containing attributes structured in this way, it extracts the DHCP Option Code and its value, then constructs the appropriate DHCP option and includes it in the DHCP Offer or DHCP ACK packet sent back to the IPoE client. + +## Configuration + +### accel-ppp Side + +The functionality is inherent to the `ipoe` module; no special configuration options are required in `accel-ppp.conf` to enable this mapping. Ensure the `ipoe` module is loaded. + +### RADIUS Server Side + +To leverage this feature, your RADIUS server must be configured to send attributes using the Vendor ID `54` (DHCP) and the desired DHCP Option Code as the Attribute ID. + +**FreeRADIUS Example:** + +1. **Ensure Dictionary Definitions:** + Your FreeRADIUS installation should have dictionary files that define Vendor 54 as "DHCP" and the relevant DHCP Option Codes as attributes within that vendor space. The `accel-ppp` project often provides a `dictionary.dhcp` file (e.g., in `accel-pppd/radius/dict/`) with these definitions: + + ```text + VENDOR DHCP 54 + ATTRIBUTE DHCP-Vendor 43 octets + # ... other DHCP option definitions + ``` + +2. **Configure Reply Attributes in `users` file (or equivalent policy):** + The format for specifying these attributes is generally `Attr-<Vendor-ID>-<Attribute-ID> = <value>`. + + * **Generic DHCP Option (e.g., Option 224, private use, with string "Hello"):** + ```text + User-Name == "test_user" + Attr-54-224 = "Hello" + ``` + + * **Option 6 (DNS Servers):** + To send a list of DNS server IP addresses (e.g., `8.8.8.8` and `8.8.4.4`). The value is the concatenation of the 4-byte IP addresses in hexadecimal. + ```text + User-Name == "test_user" + Attr-54-6 = 0x0808080808080404 + ``` + + * **Option 15 (Domain Name):** + To send a domain name string (e.g., `example.com`). + ```text + User-Name == "test_user" + Attr-54-15 = "example.com" + ``` + + * **Option 26 (Interface MTU):** + To send a specific MTU size (e.g., `1450`). The value is a 16-bit integer (2 bytes) in hexadecimal. + ```text + User-Name == "test_user" + Attr-54-26 = 0x05AA # 1450 in hex is 0x05AA + ``` + + * **Option 43 (Vendor-Specific Information):** + This option typically contains sub-options encoded in a TLV (Type-Length-Value) format. The entire TLV structure for Option 43 needs to be provided as the attribute's hexadecimal value. + + *Example: Sending sub-option `1` with value `"ABC"`* + * Sub-option Type: `1` (0x01) + * Sub-option Length: `3` (0x03) + * Sub-option Value: `"ABC"` (0x414243) + * Combined Hex Value: `0103414243` + + ```text + User-Name == "test_user" + Attr-54-43 = 0x0103414243 + ``` + + * **Option 121 (Classless Static Route):** + To send static routes. The format for the value is a sequence of `(Mask Width, Significant Octets of Destination, Router IP)`. + + *Example: Route `10.0.0.0/8` via `192.168.1.1`* + * Mask Width: `8` (0x08) + * Significant Octets of Destination: `10` (0x0a) - only 1 byte for a /8 network + * Router IP: `192.168.1.1` (0xc0a80101) + * Combined Hex Value: `080ac0a80101` + + ```text + User-Name == "test_user" + Attr-54-121 = 0x080ac0a80101 + ``` + +## Notes + +* The RADIUS attribute value must strictly be the raw payload of the DHCP option. accel-ppp automatically handles inserting the DHCP Option Code and Length fields into the final DHCP packet. +* For complex DHCP options like Option 43 (Vendor-Specific Information) and Option 121 (Classless Static Route), you must manually construct the internal structure (e.g., TLVs for Option 43) as part of the RADIUS attribute value. diff --git a/docs/pppoe_radius.md b/docs/pppoe_radius.md new file mode 100644 index 00000000..cc3f3461 --- /dev/null +++ b/docs/pppoe_radius.md @@ -0,0 +1,82 @@ +# Supplying PPPoE Session Parameters via RADIUS + +accel-ppp supports configuring PPPoE sessions dynamically via RADIUS Access-Accept attributes. Unlike IPoE which maps attributes to DHCP options, PPPoE sessions are configured using standard PPP IPCP/IPv6CP negotiation and internal session parameters. + +## Standard IPCP Configuration + +These attributes control the IPv4 configuration negotiated with the client via IPCP. + +* **Framed-IP-Address** (8) + * Assigns the IPv4 address to the client. + * Value: IPv4 address (e.g., `192.168.0.100`) or `255.255.255.254` to instruct the NAS to select an address from a pool (if configured). + +* **MS-Primary-DNS-Server** (Vendor: Microsoft, ID: 28) + * Primary DNS server address to send to the client. + +* **MS-Secondary-DNS-Server** (Vendor: Microsoft, ID: 29) + * Secondary DNS server address. + +* **MS-Primary-NBNS-Server** (Vendor: Microsoft, ID: 30) + * Primary NetBIOS/WINS server address. + +* **MS-Secondary-NBNS-Server** (Vendor: Microsoft, ID: 31) + * Secondary NetBIOS/WINS server address. + +## IPv6 Configuration + +These attributes control the IPv6 configuration negotiated via IPv6CP and DHCPv6/SLAAC. + +* **Framed-Interface-Id** (96) + * Assigns the Interface Identifier (lower 64 bits) for the client's IPv6 address. + +* **Framed-IPv6-Prefix** (97) + * Assigns an IPv6 prefix to the client (typically via SLAAC). + +* **Delegated-IPv6-Prefix** (123) + * Prefix delegation (IA_PD) via DHCPv6. + +* **Framed-IPv6-Route** (99) + * Adds a route to the client session for the specified IPv6 prefix. + * Format: `2001:db8::/32 gateway metric` + +## Routing + +* **Framed-Route** (22) + * Adds a static route to the client session. + * Format: `192.168.10.0/24 192.168.0.100 1` (Network Gateway Metric) + +## Session Management + +* **Session-Timeout** (27) + * Maximum duration of the session in seconds. The session is terminated after this time. + +* **Idle-Timeout** (28) + * Maximum idle time in seconds. The session is terminated if no traffic is detected for this duration. + +* **Acct-Interim-Interval** (85) + * Interval in seconds for sending Interim-Update accounting packets. + +* **Accel-VRF-Name** (Vendor: Accel-PPP, ID: 1) + * Assigns the session to a specific VRF (Virtual Routing and Forwarding) context. + +## Rate Limiting (Shaper) + +The `shaper` module can be configured to listen for specific RADIUS attributes to apply bandwidth limits. By default, it uses `Filter-Id`. + +* **Filter-Id** (11) + * Used to specify upload/download limits. + * **Simple Format:** `speed` (bits/sec) or `speed/burst`. + * Example: `10000` (10 Mbps) + * **Cisco Format:** `rate-limit output access-group 1 8000000 1500000 3000000` (downstream) / `rate-limit input ...` (upstream). + +* **Mikrotik-Rate-Limit** (Vendor: Mikrotik, ID: 8) + * Supported if the attribute is present. + +Note: The attribute ID and Vendor ID for the shaper are configurable in the `[shaper]` section of `accel-ppp.conf`. + +## PPPoE Specific Attributes + +PPPoE discovery tags (like Service-Name) are generally handled by the server configuration, but TR-101 (Broadband Forum) tags can be processed if `tr101` support is enabled. + +* **TR-101 Attributes** (Vendor: ADSL-Forum) + * accel-ppp can parse Agent-Circuit-Id and Agent-Remote-Id from PADO/PADR packets if they are present in Vendor-Specific tags, and these can be used for authentication or accounting logging. diff --git a/drivers/ipoe/CMakeLists.txt b/drivers/ipoe/CMakeLists.txt index e221a7ec..d0d6902c 100644 --- a/drivers/ipoe/CMakeLists.txt +++ b/drivers/ipoe/CMakeLists.txt @@ -3,11 +3,35 @@ if (NOT DEFINED KDIR) set(KDIR "/usr/src/linux") endif (NOT DEFINED KDIR) +# Try to figure out the kernel release once so we can show it before building. +execute_process( + COMMAND make -s -C ${KDIR} kernelrelease + RESULT_VARIABLE IPOE_KERNEL_RELEASE_RESULT + OUTPUT_VARIABLE IPOE_KERNEL_RELEASE + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET +) + +if (NOT IPOE_KERNEL_RELEASE_RESULT STREQUAL "0" OR IPOE_KERNEL_RELEASE STREQUAL "") + find_program(UNAME_EXECUTABLE uname) + + if (UNAME_EXECUTABLE) + execute_process( + COMMAND ${UNAME_EXECUTABLE} -r + OUTPUT_VARIABLE IPOE_KERNEL_RELEASE + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + else() + set(IPOE_KERNEL_RELEASE "unknown") + endif() +endif() + ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/driver/ipoe.ko COMMAND rm -rf ${CMAKE_CURRENT_BINARY_DIR}/driver COMMAND mkdir ${CMAKE_CURRENT_BINARY_DIR}/driver COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/* ${CMAKE_CURRENT_BINARY_DIR}/driver COMMAND ln -sf ${CMAKE_BINARY_DIR}/version.h ${CMAKE_CURRENT_BINARY_DIR}/driver + COMMAND ${CMAKE_COMMAND} -E echo "[ 99%] Generating driver/ipoe.ko for kernel ${IPOE_KERNEL_RELEASE}" COMMAND make -C ${KDIR} M=${CMAKE_CURRENT_BINARY_DIR}/driver modules DEPENDS ipoe.c ipoe.h ) diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c index fa7dec3f..2829e6ac 100644 --- a/drivers/ipoe/ipoe.c +++ b/drivers/ipoe/ipoe.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/if_ether.h> #include <linux/if_vlan.h> +#include <linux/ipv6.h> #include <linux/semaphore.h> #include <linux/netfilter_ipv4.h> #include <linux/u64_stats_sync.h> @@ -26,6 +27,9 @@ #include <net/ip.h> #include <net/icmp.h> #include <net/flow.h> +#ifdef flowi4_dscp +#include <net/inet_dscp.h> +#endif #include <net/xfrm.h> #include <net/net_namespace.h> #include <net/netns/generic.h> @@ -58,6 +62,23 @@ #define RHEL_MAJOR 0 #endif +/* ipv6.disable=1 leaves the IPv6 FIB uninitialized, so ip6_route_output() + * oopses; ipv6_mod_enabled() detects that (and CONFIG_IPV6=n) since 4.8 */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,8,0) +#define ipoe_ipv6_enabled() ipv6_mod_enabled() +#else +#define ipoe_ipv6_enabled() 1 +#endif + +static inline void ipoe_flowi4_set_tos(struct flowi4 *fl4, __u8 dsfield) +{ +#ifdef flowi4_dscp + fl4->flowi4_dscp = inet_dsfield_to_dscp(dsfield); +#else + fl4->flowi4_tos = dsfield; +#endif +} + struct ipoe_stats { struct u64_stats_sync sync; u64 packets; @@ -263,7 +284,7 @@ static int check_nat_required(struct sk_buff *skb, struct net_device *link) memset(&fl4, 0, sizeof(fl4)); fl4.daddr = iph->daddr; - fl4.flowi4_tos = RT_TOS(0); + ipoe_flowi4_set_tos(&fl4, RT_TOS(0)); fl4.flowi4_scope = RT_SCOPE_UNIVERSE; rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) @@ -702,7 +723,11 @@ nl_err: if (!list_empty(&ipoe_list2_u)) mod_timer(&ipoe_timer_u, jiffies + IPOE_TIMEOUT_U * HZ); else +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,2,0) del_timer(&ipoe_timer_u); +#else + timer_delete(&ipoe_timer_u); +#endif } static struct ipoe_session *ipoe_lookup(__be32 addr) @@ -767,7 +792,7 @@ static struct ipoe_session *ipoe_lookup_rt4(struct sk_buff *skb, __be32 addr, st memset(&fl4, 0, sizeof(fl4)); fl4.daddr = addr; - fl4.flowi4_tos = RT_TOS(0); + ipoe_flowi4_set_tos(&fl4, RT_TOS(0)); fl4.flowi4_scope = RT_SCOPE_UNIVERSE; rt = ip_route_output_key(net, &fl4); if (IS_ERR(rt)) @@ -874,6 +899,9 @@ static rx_handler_result_t ipoe_recv(struct sk_buff **pskb) return RX_HANDLER_CONSUMED; } } else if (skb->protocol == htons(ETH_P_IPV6)) { + if (!ipoe_ipv6_enabled()) + return RX_HANDLER_PASS; + if (!pskb_may_pull(skb, sizeof(*ip6h) + noff)) return RX_HANDLER_PASS; @@ -1105,7 +1133,13 @@ static void ipoe_netdev_setup(struct net_device *dev) dev->iflink = 0; #endif dev->addr_len = ETH_ALEN; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,15,0) + dev->netns_immutable = true; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(6,12,0) + dev->netns_local = true; +#else dev->features |= NETIF_F_NETNS_LOCAL; +#endif dev->features &= ~(NETIF_F_HW_VLAN_FILTER | NETIF_F_LRO); dev->header_ops = &ipoe_hard_header_ops; dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; @@ -1984,8 +2018,11 @@ static void __exit ipoe_fini(void) flush_work(&ipoe_queue_work); skb_queue_purge(&ipoe_queue); - +#if LINUX_VERSION_CODE < KERNEL_VERSION(6,2,0) del_timer(&ipoe_timer_u); +#else + timer_delete(&ipoe_timer_u); +#endif for (i = 0; i <= IPOE_HASH_BITS; i++) rcu_assign_pointer(ipoe_list[i].next, &ipoe_list[i]); diff --git a/drivers/vlan_mon/vlan_mon.c b/drivers/vlan_mon/vlan_mon.c index d5f42c91..8b699230 100644 --- a/drivers/vlan_mon/vlan_mon.c +++ b/drivers/vlan_mon/vlan_mon.c @@ -753,6 +753,9 @@ static int __init vlan_mon_init(void) } #endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,6,0) + vlan_pt.af_packet_net = &init_net; +#endif dev_add_pack(&vlan_pt); return 0; diff --git a/tests/README.md b/tests/README.md index d062ed46..689a16d8 100644 --- a/tests/README.md +++ b/tests/README.md @@ -6,7 +6,7 @@ These tests are done for Ubuntu and Debian distros. Please use latest stable Deb Install pytest -Using apt: `sudo apt install python3-pytest python3-pytest-dependency` or using pip: `sudo pip3 install pytest pytest-dependency`. +Using apt: `sudo apt install python3-pytest python3-pytest-dependency python3-pytest-order` or using pip: `sudo pip3 install pytest pytest-dependency pytest-order`. pytest-dependency version must be >= 0.5 (with 'scope' support) @@ -43,13 +43,13 @@ sudo insmod build/drivers/ipoe/driver/ipoe.ko ```bash # from this dir (tests) -sudo python3 -m pytest -Wall -v +sudo python3 -m pytest -Wall --order-dependencies -v ``` To skip tests related to ipoe and vlan_mon kernel modules: ```bash # from this dir (tests) -sudo python3 -m pytest -Wall -v -m "not ipoe_driver and not vlan_mon_driver" +sudo python3 -m pytest -Wall --order-dependencies -v -m "not ipoe_driver and not vlan_mon_driver" ``` ## Preparations (for coverage report) @@ -83,7 +83,7 @@ Then insert kernel modules (ipoe.ko and vlan-mon.ko) ```bash # from root dir (parent for this dir) -sudo python3 -m pytest -Wall tests -v # execute tests to collect coverage data +sudo python3 -m pytest -Wall --order-dependencies tests -v # execute tests to collect coverage data mkdir tests/report gcovr --config=tests/gcovr.conf # default report gcovr --config=tests/gcovr.conf --csv # csv report diff --git a/tests/accel-pppd/test_basic.py b/tests/accel-pppd/general/test_basic.py index 2b2c6f71..9652ee0b 100644 --- a/tests/accel-pppd/test_basic.py +++ b/tests/accel-pppd/general/test_basic.py @@ -19,9 +19,11 @@ def accel_pppd_config(): log_tcp #log_pgsql + connlimit pptp l2tp sstp + radius pppoe ipoe @@ -30,7 +32,6 @@ def accel_pppd_config(): auth_chap_md5 auth_pap - radius chap-secrets ippool @@ -39,7 +40,6 @@ def accel_pppd_config(): shaper #net-snmp logwtmp - connlimit ipv6_nd ipv6_dhcp diff --git a/tests/accel-pppd/general/test_metrics.py b/tests/accel-pppd/general/test_metrics.py new file mode 100644 index 00000000..6344d3d0 --- /dev/null +++ b/tests/accel-pppd/general/test_metrics.py @@ -0,0 +1,91 @@ +import http.client +import json + +import pytest + + +PROM_PORT = 9099 + + +def _config(fmt): + return f""" + [modules] + metrics + + [core] + log-error=/dev/stderr + + [log] + log-emerg=/dev/stderr + level=1 + + [cli] + tcp=127.0.0.1:2001 + + [metrics] + address=127.0.0.1:{PROM_PORT} + format={fmt} + """ + + +def _request(path, method="GET"): + conn = http.client.HTTPConnection("127.0.0.1", PROM_PORT, timeout=5) + try: + conn.request(method, path) + resp = conn.getresponse() + body = resp.read().decode("utf-8", "replace") + headers = {k.lower(): v for k, v in resp.getheaders()} + return resp.status, headers, body + finally: + conn.close() + + +class TestPrometheus: + @pytest.fixture() + def accel_pppd_config(self): + return _config("prometheus") + + def test_metrics_prometheus(self, accel_pppd_instance): + assert accel_pppd_instance + + status, headers, body = _request("/metrics") + + assert status == 200 + assert "text/plain" in headers.get("content-type", "") + assert "accel_ppp_build_info{version=" in body + assert "# TYPE accel_ppp_uptime_seconds gauge" in body + assert 'accel_ppp_sessions{state="active"}' in body + + def test_metrics_404_unknown_path(self, accel_pppd_instance): + assert accel_pppd_instance + + status, _, _ = _request("/nope") + + assert status == 404 + + def test_metrics_405_non_get(self, accel_pppd_instance): + assert accel_pppd_instance + + status, _, _ = _request("/metrics", method="POST") + + assert status == 405 + + +class TestJson: + @pytest.fixture() + def accel_pppd_config(self): + return _config("json") + + def test_metrics_json(self, accel_pppd_instance): + assert accel_pppd_instance + + status, headers, body = _request("/metrics") + + assert status == 200 + assert headers.get("content-type") == "application/json" + + doc = json.loads(body) + assert "build" in doc and "version" in doc["build"] + assert "uptime_seconds" in doc + assert "active" in doc["sessions"] + assert "threads" in doc["core"] diff --git a/tests/accel-pppd/general/test_pcre_negative_cases.py b/tests/accel-pppd/general/test_pcre_negative_cases.py new file mode 100644 index 00000000..698c83ab --- /dev/null +++ b/tests/accel-pppd/general/test_pcre_negative_cases.py @@ -0,0 +1,65 @@ +import pytest +from common import process + + +@pytest.fixture() +def accel_pppd_config(): + return """ + [modules] + radius + pppoe + + [core] + log-error=/dev/stderr + + [log] + log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr + level=5 + + [cli] + tcp=127.0.0.1:2001 + + [radius] + + [pppoe] + """ + + +# test pcre-related negative cases +def test_pcre_negative_cases(accel_pppd_instance, accel_cmd): + + # test that accel-pppd started successfully + assert accel_pppd_instance + + (exit_sh_sess, out_sh_sess, err_sh_sess) = process.run([accel_cmd, "show sessions match username 00("]) + # test that 'show sessions' with invalid regexp reports the issue and error position + assert ( + exit_sh_sess == 0 + and len(out_sh_sess) > 0 + and err_sh_sess == "" + and "match: " in out_sh_sess + and "at 3" in out_sh_sess + ) + + + (exit_iface_add, out_iface_add, err_iface_add) = process.run([accel_cmd, "pppoe interface add re:000("]) + # test that 'pppoe interface add' with invalid regexp reports the issue and error position + assert ( + exit_iface_add == 0 + and len(out_iface_add) > 0 + and err_iface_add == "" + and "pppoe: " in out_iface_add + and "at 4" in out_iface_add + ) + + (exit_term, out_term, err_term) = process.run([accel_cmd, "terminate match username 00("]) + # test that 'terminate' with invalid regexp reports the issue and error position + assert ( + exit_term == 0 + and len(out_term) > 0 + and err_term == "" + and "match: " in out_term + and "at 3" in out_term + ) diff --git a/tests/accel-pppd/ipoe/conftest.py b/tests/accel-pppd/ipoe/conftest.py index 3db8dd60..353ed270 100644 --- a/tests/accel-pppd/ipoe/conftest.py +++ b/tests/accel-pppd/ipoe/conftest.py @@ -1,5 +1,5 @@ import pytest -from common import dhclient_process +from common import dhclient_process, config import tempfile, os # dhclient executable file name @@ -44,3 +44,21 @@ def dhclient_instance(accel_pppd_instance, veth_pair_netns, dhclient, dhclient_a # test teardown: dhclient_process.end(dhclient_thread, dhclient_control) + +# lua script as string (should be redefined by specific test) +@pytest.fixture() +def lua_script(): + return "" + + +# lua script file name +@pytest.fixture() +def lua_script_file(lua_script): + # test setup: + filename = config.make_tmp(lua_script) + + # test execution + yield filename + + # test teardown: + config.delete_tmp(filename) diff --git a/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_chap_secrets.py b/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_chap_secrets.py new file mode 100644 index 00000000..80c559da --- /dev/null +++ b/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_chap_secrets.py @@ -0,0 +1,92 @@ +import pytest +from common import process +import time + + +@pytest.fixture() +def chap_secrets_config(veth_pair_netns): + return veth_pair_netns["veth_a"] + " * pass123 192.0.2.57" + + +@pytest.fixture() +def accel_pppd_config(veth_pair_netns, chap_secrets_config_file): + print( + "accel_pppd_config veth_pair_netns: " + + str(veth_pair_netns) + + "chap_secrets_config_file: " + + str(chap_secrets_config_file) + ) + return ( + """ + [modules] + connlimit + chap-secrets + ipoe + + [cli] + tcp=127.0.0.1:2001 + + [core] + log-error=/dev/stderr + + [log] + log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr + level=5 + + [ipoe] + username=ifname + password=pass123 + verbose=5 + start=dhcpv4 + shared=1 + gw-ip-address=192.0.2.1/24 + interface=re:.""" + + veth_pair_netns["veth_a"][1:] + + """ + [chap-secrets] + chap-secrets=""" + + chap_secrets_config_file + ) + + +# test dhcpv4 shared session without auth check +@pytest.mark.dependency(depends=["ipoe_driver_loaded"], scope="session") +@pytest.mark.ipoe_driver +@pytest.mark.chap_secrets +def test_ipoe_shared_session_chap_secrets( + dhclient_instance, accel_cmd, veth_pair_netns +): + + # test that dhclient (with accel-pppd) started successfully + assert dhclient_instance["is_started"] + + # wait until session is started + max_wait_time = 10.0 + sleep_time = 0.0 + is_started = False # is session started + while sleep_time < max_wait_time: + (exit, out, err) = process.run( + [ + accel_cmd, + "show sessions called-sid,ip,state", + ] + ) + assert exit == 0 # accel-cmd fails + # print(out) + if veth_pair_netns["veth_a"] in out and "192.0.2.57" in out and "active" in out: + # session is found + print( + "test_ipoe_session_chap_secrets: session found in (sec): " + + str(sleep_time) + ) + is_started = True + break + time.sleep(0.1) + sleep_time += 0.1 + + print("test_ipoe_shared_session_chap_secrets: last accel-cmd out: " + out) + + # test that session is started + assert is_started == True diff --git a/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_lua_chap_secrets.py b/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_lua_chap_secrets.py new file mode 100644 index 00000000..fdee7c4a --- /dev/null +++ b/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_lua_chap_secrets.py @@ -0,0 +1,112 @@ +import pytest +from common import process +import time + + +# create vlan 335 on both interfaces of pair +@pytest.fixture() +def veth_pair_vlans_config(): + return {"vlans_a": [335], "vlans_b": [335]} + + +# use vlan as a username +@pytest.fixture() +def chap_secrets_config(veth_pair_netns): + return "335 * pass123 192.0.2.67" + + +# return vlan as a username +@pytest.fixture() +def lua_script(): + return """#!lua + function vlan_func(pkt) + return pkt:vlan() + end""" + + +@pytest.fixture() +def accel_pppd_config(veth_pair_netns, chap_secrets_config_file, lua_script_file): + print( + "accel_pppd_config veth_pair_netns: " + + str(veth_pair_netns) + + "chap_secrets_config_file: " + + str(chap_secrets_config_file) + ) + return ( + """ + [modules] + connlimit + chap-secrets + ipoe + + [cli] + tcp=127.0.0.1:2001 + + [core] + log-error=/dev/stderr + + [log] + log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr + level=5 + + [ipoe] + lua-file=""" + + lua_script_file + + """ + username=lua:vlan_func + password=pass123 + verbose=5 + start=dhcpv4 + shared=1 + gw-ip-address=192.0.2.1/24 + interface=re:.""" + + veth_pair_netns["veth_a"][1:] + + "\\.335" + + """ + [chap-secrets] + chap-secrets=""" + + chap_secrets_config_file + ) + + +# test dhcpv4 shared session without auth check +@pytest.mark.dependency(depends=["ipoe_driver_loaded"], scope="session") +@pytest.mark.ipoe_driver +@pytest.mark.chap_secrets +def test_ipoe_shared_session_lua_chap_secrets( + dhclient_instance, accel_cmd, veth_pair_netns +): + + # test that dhclient (with accel-pppd) started successfully + assert dhclient_instance["is_started"] + + # wait until session is started + max_wait_time = 10.0 + sleep_time = 0.0 + is_started = False # is session started + while sleep_time < max_wait_time: + (exit, out, err) = process.run( + [ + accel_cmd, + "show sessions called-sid,ip,state", + ] + ) + assert exit == 0 # accel-cmd fails + # print(out) + if veth_pair_netns["veth_a"] in out and "192.0.2.67" in out and "active" in out: + # session is found + print( + "test_ipoe_session_lua_chap_secrets: session found in (sec): " + + str(sleep_time) + ) + is_started = True + break + time.sleep(0.1) + sleep_time += 0.1 + + print("test_ipoe_shared_session_lua_chap_secrets: last accel-cmd out: " + out) + + # test that session is started + assert is_started == True diff --git a/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_wo_auth.py b/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_wo_auth.py index 104e4e9b..7ebb420a 100644 --- a/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_wo_auth.py +++ b/tests/accel-pppd/ipoe/dhcpv4/test_ipoe_shared_session_wo_auth.py @@ -9,7 +9,8 @@ def accel_pppd_config(veth_pair_netns): return ( """ [modules] - pppoe + connlimit + radius ipoe ippool @@ -20,16 +21,23 @@ def accel_pppd_config(veth_pair_netns): [cli] tcp=127.0.0.1:2001 + [core] + log-error=/dev/stderr + [log] log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr level=5 + [radius] + [ipoe] noauth=1 shared=1 gw-ip-address=192.0.2.1/24 - interface=""" - + veth_pair_netns["veth_a"] + interface=re:.""" + + veth_pair_netns["veth_a"][1:] ) diff --git a/tests/accel-pppd/pppoe/conftest.py b/tests/accel-pppd/pppoe/conftest.py index 8ebaaed3..b3893200 100644 --- a/tests/accel-pppd/pppoe/conftest.py +++ b/tests/accel-pppd/pppoe/conftest.py @@ -1,5 +1,6 @@ -import pytest +import pytest, subprocess, re from common import pppd_process +from packaging.version import Version # pppd executable file name @pytest.fixture() @@ -13,11 +14,21 @@ def pppd(pytestconfig): def pppd_config(): return "" +# determines which plugin is required - pppoe.so (pppd 2.5.0+) or rp-pppoe.so (pppd <2.5.0) +def pppd_plugin_so(pppd): + command = [pppd, "--version"] + result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + pppd_version = Version(re.search(r'\d+\.\d+\.\d+', result.stdout + result.stderr).group()) + ref_version = Version("2.5.0") + if pppd_version >= ref_version: + return "pppoe.so" + else: + return "rp-pppoe.so" # pppd configuration as command line args @pytest.fixture() -def pppd_args(pppd_config): - return pppd_config.split() +def pppd_args(pppd_config, pppd): + return ("plugin " + pppd_plugin_so(pppd) + "\n" + pppd_config).split() # setup and teardown for tests that required running pppd (after accel-pppd) diff --git a/tests/accel-pppd/pppoe/test_pppoe_disc.py b/tests/accel-pppd/pppoe/test_pppoe_disc.py index eb069c42..64a0d295 100644 --- a/tests/accel-pppd/pppoe/test_pppoe_disc.py +++ b/tests/accel-pppd/pppoe/test_pppoe_disc.py @@ -8,15 +8,23 @@ def accel_pppd_config(veth_pair_netns): return ( """ [modules] + radius pppoe + [core] + log-error=/dev/stderr + [log] log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr level=5 [cli] tcp=127.0.0.1:2001 + [radius] + [pppoe] ac-name=test-accel interface=""" diff --git a/tests/accel-pppd/pppoe/test_pppoe_pado_delay.py b/tests/accel-pppd/pppoe/test_pppoe_pado_delay.py index 96c73bf8..3a93d920 100644 --- a/tests/accel-pppd/pppoe/test_pppoe_pado_delay.py +++ b/tests/accel-pppd/pppoe/test_pppoe_pado_delay.py @@ -30,15 +30,23 @@ def accel_pppd_config(veth_pair_netns): return ( """ [modules] + radius pppoe + [core] + log-error=/dev/stderr + [log] log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr level=5 [cli] tcp=127.0.0.1:2001 + [radius] + [pppoe] ac-name=test-accel pado-delay=1500 diff --git a/tests/accel-pppd/pppoe/test_pppoe_session_chap_secrets.py b/tests/accel-pppd/pppoe/test_pppoe_session_chap_secrets.py new file mode 100644 index 00000000..05d19701 --- /dev/null +++ b/tests/accel-pppd/pppoe/test_pppoe_session_chap_secrets.py @@ -0,0 +1,104 @@ +import pytest +from common import process +import time + + +@pytest.fixture() +def chap_secrets_config(): + return "loginCSAB * pass123 192.0.2.37" + + +@pytest.fixture() +def accel_pppd_config(veth_pair_netns, chap_secrets_config_file): + print( + "accel_pppd_config veth_pair_netns: " + + str(veth_pair_netns) + + "chap_secrets_config_file" + + str(chap_secrets_config_file) + ) + return ( + """ + [modules] + chap-secrets + pppoe + auth_pap + + [core] + log-error=/dev/stderr + + [log] + log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr + level=5 + + [cli] + tcp=127.0.0.1:2001 + + [pppoe] + interface=""" + + veth_pair_netns["veth_a"] + + """ + [chap-secrets] + gw-ip-address=192.0.2.1 + chap-secrets=""" + + chap_secrets_config_file + ) + + +@pytest.fixture() +def pppd_config(veth_pair_netns): + print("pppd_config veth_pair_netns: " + str(veth_pair_netns)) + return ( + """ + nodetach + noipdefault + defaultroute + connect /bin/true + noauth + persist + mtu 1492 + noaccomp + default-asyncmap + user loginCSAB + password pass123 + nic-""" + + veth_pair_netns["veth_b"] + ) + + +# test pppoe session without auth check +@pytest.mark.chap_secrets +def test_pppoe_session_chap_secrets(pppd_instance, accel_cmd): + + # test that pppd (with accel-pppd) started successfully + assert pppd_instance["is_started"] + + # wait until session is started + max_wait_time = 10.0 + sleep_time = 0.0 + is_started = False # is session started + while sleep_time < max_wait_time: + (exit, out, err) = process.run( + [ + accel_cmd, + "show sessions match username log.nCSAB username,ip,state", + ] + ) + assert exit == 0 # accel-cmd fails + # print(out) + if "loginCSAB" in out and "192.0.2.37" in out and "active" in out: + # session is found + print( + "test_pppoe_session_chap_secrets: session found in (sec): " + + str(sleep_time) + ) + is_started = True + break + time.sleep(0.1) + sleep_time += 0.1 + + print("test_pppoe_session_chap_secrets: last accel-cmd out: " + out) + + # test that session is started + assert is_started == True diff --git a/tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py b/tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py index 0c8aa2c0..960b7c94 100644 --- a/tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py +++ b/tests/accel-pppd/pppoe/test_pppoe_session_wo_auth.py @@ -9,12 +9,18 @@ def accel_pppd_config(veth_pair_netns): return ( """ [modules] + radius pppoe auth_pap ippool + [core] + log-error=/dev/stderr + [log] log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr level=5 [auth] @@ -27,6 +33,8 @@ def accel_pppd_config(veth_pair_netns): [cli] tcp=127.0.0.1:2001 + [radius] + [pppoe] interface=""" + veth_pair_netns["veth_a"] @@ -47,7 +55,6 @@ def pppd_config(veth_pair_netns): mtu 1492 noaccomp default-asyncmap - plugin rp-pppoe.so user loginAB password pass123 nic-""" @@ -69,7 +76,7 @@ def test_pppoe_session_wo_auth(pppd_instance, accel_cmd): (exit, out, err) = process.run( [ accel_cmd, - "show sessions match username loginAB username,ip,state", + "show sessions match username log.nAB username,ip,state", ] ) assert exit == 0 # accel-cmd fails diff --git a/tests/accel-pppd/pppoe/test_pppoe_vlan_mon.py b/tests/accel-pppd/pppoe/test_pppoe_vlan_mon.py index 670abc33..b73189c3 100644 --- a/tests/accel-pppd/pppoe/test_pppoe_vlan_mon.py +++ b/tests/accel-pppd/pppoe/test_pppoe_vlan_mon.py @@ -13,15 +13,23 @@ def accel_pppd_config(veth_pair_netns): print(veth_pair_netns) return """ [modules] + radius pppoe + [core] + log-error=/dev/stderr + [log] log-debug=/dev/stdout + log-file=/dev/stdout + log-emerg=/dev/stderr level=5 [cli] tcp=127.0.0.1:2001 + [radius] + [pppoe] ac-name=test-accel vlan-mon=%s,10-20 diff --git a/tests/conftest.py b/tests/conftest.py index d3733409..da1f40f4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -26,6 +26,10 @@ def pytest_configure(config): "markers", "vlan_mon_driver: marks tests as related to ipoe kernel module (deselect with '-m \"not vlan_mon_driver\"')", ) + config.addinivalue_line( + "markers", + "chap_secrets: marks tests as related to chap-secrets module (deselect with '-m \"not chap_secrets\"')", + ) # accel-pppd executable file name @@ -97,3 +101,21 @@ def veth_pair_netns(veth_pair_vlans_config): # test teardown: veth.delete_veth_pair_netns(veth_pair_netns_instance) + +# chap-secrets configuration as string (should be redefined by specific test) +@pytest.fixture() +def chap_secrets_config(): + return "" + + +# chap-secrets configuration file name +@pytest.fixture() +def chap_secrets_config_file(chap_secrets_config): + # test setup: + filename = config.make_tmp(chap_secrets_config) + + # test execution + yield filename + + # test teardown: + config.delete_tmp(filename) |
