From 64f7836804ce96ccf81c8787bdcf11b7601c9881 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 24 Nov 2025 23:16:02 +0100 Subject: [PATCH 01/33] Switch to 25.11 --- flake.lock | 16 ++++++++-------- flake.nix | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/flake.lock b/flake.lock index 7c92712..033ae95 100644 --- a/flake.lock +++ b/flake.lock @@ -263,16 +263,16 @@ ] }, "locked": { - "lastModified": 1758463745, - "narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=", + "lastModified": 1764177491, + "narHash": "sha256-dhX2abFWxeXab3Aad4Pg1xGtn9W84/qetNXfmYUwktw=", "owner": "nix-community", "repo": "home-manager", - "rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3", + "rev": "2217780c39169a9c77915200137550c2ef0fa974", "type": "github" }, "original": { "owner": "nix-community", - "ref": "release-25.05", + "ref": "release-25.11", "repo": "home-manager", "type": "github" } @@ -418,16 +418,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1763334038, - "narHash": "sha256-LBVOyaH6NFzQ3X/c6vfMZ9k4SV2ofhpxeL9YnhHNJQQ=", + "lastModified": 1764522689, + "narHash": "sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD+/cTUzzgVFoaHrkqY=", "owner": "nixos", "repo": "nixpkgs", - "rev": "4c8cdd5b1a630e8f72c9dd9bf582b1afb3127d2c", + "rev": "8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f", "type": "github" }, "original": { "owner": "nixos", - "ref": "nixos-25.05", + "ref": "nixos-25.11", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index d56e73d..d9aa7f3 100644 --- a/flake.nix +++ b/flake.nix @@ -19,7 +19,7 @@ }; home-manager = { - url = "github:nix-community/home-manager/release-25.05"; + url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs"; }; @@ -43,7 +43,7 @@ nixos-hardware.url = "github:nixos/nixos-hardware/master"; - nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; nixpkgsMaster.url = "github:NixOS/nixpkgs/master"; From c2f5a2dd9ca619db325d46ed3d31960029ec7d7e Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 10:00:14 +0100 Subject: [PATCH 02/33] Bump lanzaboote version --- flake.lock | 57 +++++++++++++++++++----------------------------------- flake.nix | 2 +- 2 files changed, 21 insertions(+), 38 deletions(-) diff --git a/flake.lock b/flake.lock index 033ae95..2ee5fbd 100644 --- a/flake.lock +++ b/flake.lock @@ -45,11 +45,11 @@ }, "crane": { "locked": { - "lastModified": 1731098351, - "narHash": "sha256-HQkYvKvaLQqNa10KEFGgWHfMAbWBfFp+4cAgkut+NNE=", + "lastModified": 1754269165, + "narHash": "sha256-0tcS8FHd4QjbCVoxN9jI+PjHgA4vc/IjkUSp+N3zy0U=", "owner": "ipetkov", "repo": "crane", - "rev": "ef80ead953c1b28316cc3f8613904edc2eb90c28", + "rev": "444e81206df3f7d92780680e45858e31d2f07a08", "type": "github" }, "original": { @@ -81,11 +81,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1747046372, + "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", "type": "github" }, "original": { @@ -118,11 +118,11 @@ ] }, "locked": { - "lastModified": 1730504689, - "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=", + "lastModified": 1754091436, + "narHash": "sha256-XKqDMN1/Qj1DKivQvscI4vmHfDfvYR2pfuFOJiCeewM=", "owner": "hercules-ci", "repo": "flake-parts", - "rev": "506278e768c2a08bec68eb62932193e341f55c90", + "rev": "67df8c627c2c39c41dbec76a1f201929929ab0bd", "type": "github" }, "original": { @@ -327,16 +327,16 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1737639419, - "narHash": "sha256-AEEDktApTEZ5PZXNDkry2YV2k6t0dTgLPEmAZbnigXU=", + "lastModified": 1762205063, + "narHash": "sha256-If6vQ+KvtKs3ARBO9G3l+4wFSCYtRBrwX1z+I+B61wQ=", "owner": "nix-community", "repo": "lanzaboote", - "rev": "a65905a09e2c43ff63be8c0e86a93712361f871e", + "rev": "88b8a563ff5704f4e8d8e5118fb911fa2110ca05", "type": "github" }, "original": { "owner": "nix-community", - "ref": "v0.4.2", + "ref": "v0.4.3", "repo": "lanzaboote", "type": "github" } @@ -432,22 +432,6 @@ "type": "github" } }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1730741070, - "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgsMaster": { "locked": { "lastModified": 1763473525, @@ -567,15 +551,14 @@ "nixpkgs": [ "lanzaboote", "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" + ] }, "locked": { - "lastModified": 1731363552, - "narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=", + "lastModified": 1750779888, + "narHash": "sha256-wibppH3g/E2lxU43ZQHC5yA/7kIKLGxVEnsnVK1BtRg=", "owner": "cachix", "repo": "pre-commit-hooks.nix", - "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0", + "rev": "16ec914f6fb6f599ce988427d9d94efddf25fe6d", "type": "github" }, "original": { @@ -614,11 +597,11 @@ ] }, "locked": { - "lastModified": 1731897198, - "narHash": "sha256-Ou7vLETSKwmE/HRQz4cImXXJBr/k9gp4J4z/PF8LzTE=", + "lastModified": 1761791894, + "narHash": "sha256-myRIDh+PxaREz+z9LzbqBJF+SnTFJwkthKDX9zMyddY=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "0be641045af6d8666c11c2c40e45ffc9667839b5", + "rev": "59c45eb69d9222a4362673141e00ff77842cd219", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index d9aa7f3..7b56702 100644 --- a/flake.nix +++ b/flake.nix @@ -32,7 +32,7 @@ }; lanzaboote = { - url = "github:nix-community/lanzaboote/v0.4.2"; + url = "github:nix-community/lanzaboote/v0.4.3"; inputs.nixpkgs.follows = "nixpkgs"; }; From fe6f923fb336f1579c45a77ff7511d9b136609c5 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 00:39:48 +0100 Subject: [PATCH 03/33] Revert "Use nightly build of Jameica" This reverts commit d139988fa9d8526a2c653f860dc14fbf56e555ac. --- users/jalr/modules/jameica.nix | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/users/jalr/modules/jameica.nix b/users/jalr/modules/jameica.nix index e50c86e..d9472e0 100644 --- a/users/jalr/modules/jameica.nix +++ b/users/jalr/modules/jameica.nix @@ -1,16 +1,6 @@ { nixosConfig, lib, pkgs, ... }: lib.mkIf nixosConfig.jalr.gui.enable { - home.packages = [ - ( - pkgs.jameica.overrideAttrs (_: { - version = "2.11.0-nightly"; - src = pkgs.fetchFromGitHub { - owner = "willuhn"; - repo = "jameica"; - rev = "e51bffc0e42907cbd802a644ab52810e0a36fff8"; - hash = "sha256-0KcT52dh/tJSX6q+uKkRybz33jKnYRTNDo1BftwJLAc="; - }; - }) - ) + home.packages = with pkgs; [ + jameica ]; } From 748d747c87015201fe0155a452f997a79a177d38 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Wed, 12 Nov 2025 13:39:17 +0100 Subject: [PATCH 04/33] Use stable package --- hosts/iron/services/snapcast/ledfx.nix | 2 +- modules/esphome/default.nix | 2 +- modules/pipewire.nix | 2 +- users/jalr/modules/ddev.nix | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hosts/iron/services/snapcast/ledfx.nix b/hosts/iron/services/snapcast/ledfx.nix index 99ee625..d7db19d 100644 --- a/hosts/iron/services/snapcast/ledfx.nix +++ b/hosts/iron/services/snapcast/ledfx.nix @@ -59,7 +59,7 @@ in wantedBy = [ "multi-user.target" ]; serviceConfig = { DynamicUser = "yes"; - ExecStart = "${pkgs.master.ledfx}/bin/ledfx --host 0.0.0.0 -p 8888 -c %S/ledfx"; + ExecStart = "${pkgs.ledfx}/bin/ledfx --host 0.0.0.0 -p 8888 -c %S/ledfx"; Group = "pipewire"; NoNewPrivileges = true; ProtectControlGroups = true; diff --git a/modules/esphome/default.nix b/modules/esphome/default.nix index 4edf71e..9bf4609 100644 --- a/modules/esphome/default.nix +++ b/modules/esphome/default.nix @@ -32,7 +32,7 @@ in enable = true; address = "127.0.0.1"; inherit (cfg) port; - package = pkgs.master.esphome; + package = pkgs.esphome; }; systemd.services.esphome = { diff --git a/modules/pipewire.nix b/modules/pipewire.nix index ea97fb6..51ebd94 100644 --- a/modules/pipewire.nix +++ b/modules/pipewire.nix @@ -8,7 +8,7 @@ lib.mkIf config.jalr.gui.enable { services.pipewire = { enable = true; - package = pkgs.master.pipewire; + package = pkgs.pipewire; pulse = { enable = true; }; diff --git a/users/jalr/modules/ddev.nix b/users/jalr/modules/ddev.nix index 2e154d2..2690c91 100644 --- a/users/jalr/modules/ddev.nix +++ b/users/jalr/modules/ddev.nix @@ -1,6 +1,6 @@ { nixosConfig, lib, pkgs, ... }: lib.mkIf nixosConfig.jalr.gui.enable { home.packages = [ - pkgs.master.ddev + pkgs.ddev ]; } From 685ffcd7a91c617853f019859dbba66bd1018e8e Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Wed, 12 Nov 2025 13:44:16 +0100 Subject: [PATCH 05/33] Move renamed options --- users/jalr/modules/git.nix | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/users/jalr/modules/git.nix b/users/jalr/modules/git.nix index 3cf4007..09d9c16 100644 --- a/users/jalr/modules/git.nix +++ b/users/jalr/modules/git.nix @@ -9,17 +9,15 @@ in programs = { git = { enable = true; - userName = "Jakob Lechner"; - userEmail = "mail@jalr.de"; signing = { key = "3044E71E3DEFF49B586CF5809BF4FCCB90854DA9"; signByDefault = false; }; - diff-so-fancy = { - enable = true; - markEmptyLines = false; - }; - extraConfig = { + settings = { + user = { + name = "Jakob Lechner"; + email = "mail@jalr.de"; + }; init.defaultBranch = "main"; diff.sops.textconv = "${pkgs.sops}/bin/sops -d"; pull.ff = "only"; @@ -44,6 +42,11 @@ in }; lfs.enable = true; }; + diff-so-fancy = { + enable = true; + enableGitIntegration = true; + settings.markEmptyLines = false; + }; lazygit = { enable = true; settings = { From 8d6a4b11757771bc9854394e696b6e1242132a6b Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Wed, 12 Nov 2025 15:31:50 +0100 Subject: [PATCH 06/33] =?UTF-8?q?Use=20`nixos-rebuild-ng=E2=80=99=20in=20p?= =?UTF-8?q?lace=20of=20=E2=80=98nixos-rebuild=E2=80=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/default.nix b/modules/default.nix index cd6a1cf..a697b78 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -67,6 +67,8 @@ ]; }; + system.rebuild.enableNg = true; + programs.nano.enable = false; security.acme = { From e75d51a166ee6bea65b122c9dd21328df1c06d7b Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 24 Nov 2025 23:18:32 +0100 Subject: [PATCH 07/33] Remove obsolete option The 'virtualisation.libvirtd.qemu.ovmf' submodule has been removed. All OVMF images distributed with QEMU are now available by default. --- modules/libvirt.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/libvirt.nix b/modules/libvirt.nix index b93f8c8..e398bfe 100644 --- a/modules/libvirt.nix +++ b/modules/libvirt.nix @@ -17,7 +17,6 @@ in virtualisation = { libvirtd = { enable = true; - qemu.ovmf.enable = true; # start: starts all guests that were running prior to shutdown # ignore: only start guests which are marked as autostart From 64a9e9bb8809f4e4c1bc7cebe14e20745d9fd1ae Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 24 Nov 2025 23:20:16 +0100 Subject: [PATCH 08/33] Fix package name 'tor-browser-bundle-bin' has been renamed to/replaced by 'tor-browser' --- users/jalr/modules/tor-browser.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/users/jalr/modules/tor-browser.nix b/users/jalr/modules/tor-browser.nix index f0420ab..5e7521a 100644 --- a/users/jalr/modules/tor-browser.nix +++ b/users/jalr/modules/tor-browser.nix @@ -1,6 +1,6 @@ { nixosConfig, lib, pkgs, ... }: lib.mkIf nixosConfig.jalr.gui.enable { home.packages = with pkgs; [ - tor-browser-bundle-bin + tor-browser ]; } From f40528072423de87087aa15453c54a81adebb333 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 24 Nov 2025 23:21:08 +0100 Subject: [PATCH 09/33] Rename runCommandNoCC 'runCommandNoCC' has been renamed to/replaced by 'runCommand' --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 7b56702..56a931e 100644 --- a/flake.nix +++ b/flake.nix @@ -225,7 +225,7 @@ sops.secrets = let secretFile = config.sops.defaultSopsFile; - getSecrets = file: builtins.fromJSON (builtins.readFile (pkgs.runCommandNoCC "secretKeys" { } ''${pkgs.yq-go}/bin/yq -o json '[del .sops | .. | select(tag != "!!seq" and tag != "!!map") | path | join("/")]' ${file} > $out'')); + getSecrets = file: builtins.fromJSON (builtins.readFile (pkgs.runCommand "secretKeys" { } ''${pkgs.yq-go}/bin/yq -o json '[del .sops | .. | select(tag != "!!seq" and tag != "!!map") | path | join("/")]' ${file} > $out'')); secretNames = getSecrets secretFile; secrets = if builtins.pathExists secretFile then From ee01378e9cb5a279aad7411b950810cce6e5debf Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 24 Nov 2025 23:23:32 +0100 Subject: [PATCH 10/33] Remove mute-indicator --- modules/default.nix | 1 - modules/mute-indicator.nix | 5 -- pkgs/default.nix | 1 - pkgs/mute-indicator/.gitignore | 3 - pkgs/mute-indicator/README.md | 8 --- pkgs/mute-indicator/default.nix | 21 ------- pkgs/mute-indicator/platformio.ini | 24 -------- .../pulseaudio_mute_indicator/__init__.py | 1 - .../pulseaudio_mute_indicator/service.py | 28 --------- pkgs/mute-indicator/setup.py | 20 ------- pkgs/mute-indicator/src/main.cpp | 60 ------------------- users/jalr/modules/default.nix | 1 - users/jalr/modules/mute-indicator.nix | 18 ------ 13 files changed, 191 deletions(-) delete mode 100644 modules/mute-indicator.nix delete mode 100644 pkgs/mute-indicator/.gitignore delete mode 100644 pkgs/mute-indicator/README.md delete mode 100644 pkgs/mute-indicator/default.nix delete mode 100644 pkgs/mute-indicator/platformio.ini delete mode 100644 pkgs/mute-indicator/pulseaudio_mute_indicator/__init__.py delete mode 100644 pkgs/mute-indicator/pulseaudio_mute_indicator/service.py delete mode 100644 pkgs/mute-indicator/setup.py delete mode 100644 pkgs/mute-indicator/src/main.cpp delete mode 100644 users/jalr/modules/mute-indicator.nix diff --git a/modules/default.nix b/modules/default.nix index a697b78..38dc354 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -33,7 +33,6 @@ ./mailserver ./matrix ./mobile-network.nix - ./mute-indicator.nix ./neo.nix ./networking ./nix.nix diff --git a/modules/mute-indicator.nix b/modules/mute-indicator.nix deleted file mode 100644 index cd56106..0000000 --- a/modules/mute-indicator.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ - services.udev.extraRules = '' - SUBSYSTEM=="tty", ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="6d75", SYMLINK+="mute-indicator" - ''; -} diff --git a/pkgs/default.nix b/pkgs/default.nix index 898812b..a1415f7 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -17,7 +17,6 @@ in }; fpvout = callPackage ./fpvout { }; illuminanced = callPackage ./illuminanced { }; - mute-indicator = callPackage ./mute-indicator { }; myintercom-doorbell = callPackage ./myintercom-doorbell { inherit poetry2nix; }; diff --git a/pkgs/mute-indicator/.gitignore b/pkgs/mute-indicator/.gitignore deleted file mode 100644 index 58e33b9..0000000 --- a/pkgs/mute-indicator/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -.pio -.pioenvs -.piolibdeps diff --git a/pkgs/mute-indicator/README.md b/pkgs/mute-indicator/README.md deleted file mode 100644 index fd3273b..0000000 --- a/pkgs/mute-indicator/README.md +++ /dev/null @@ -1,8 +0,0 @@ - -I recommend setting up a udev rule, so that the python script knows which serial port it should connect to: -```bash -echo 'SUBSYSTEM=="tty", ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="6d75", SYMLINK+="mute-indicator"' | sudo tee /etc/udev/rules.d/99-mute-indicator.rules -``` - -### Google Meet -[Greasemonkey user script to automatically unmute](https://gist.github.com/jalr/ba132ed4a7133cf4fdbc98c97bf1a9e4) diff --git a/pkgs/mute-indicator/default.nix b/pkgs/mute-indicator/default.nix deleted file mode 100644 index e80b205..0000000 --- a/pkgs/mute-indicator/default.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ python310Packages }: - -python310Packages.buildPythonApplication rec { - pname = "mute-indicator"; - version = "0.0.1"; - - src = ./.; - - propagatedBuildInputs = with python310Packages; [ - python - pulsectl - pyserial - ]; - - # installPhase = '' - # echo $src - # mkdir -p $out/bin - # cp pulseaudio-mute-indicator.py $out/bin/pulseaudio-mute-indicator - # chmod +x $out/bin/pulseaudio-mute-indicator - # ''; -} diff --git a/pkgs/mute-indicator/platformio.ini b/pkgs/mute-indicator/platformio.ini deleted file mode 100644 index 0585428..0000000 --- a/pkgs/mute-indicator/platformio.ini +++ /dev/null @@ -1,24 +0,0 @@ -[env:bluepill] -framework = arduino -platform = ststm32 -board = genericSTM32F103C8 - -board_build.mcu = stm32f103c8t6 -board_build.f_cpu = 72000000L - -upload_protocol = dfu -upload_port = anything - -lib_deps = - Adafruit NeoPixel - -build_flags = - -D USBCON - -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC - -D USBD_VID=0x1EAF - -D USBD_PID=0x6d75 - -D USB_MANUFACTURER_STRING="\"github.com/jalr\"" - -D USB_PRODUCT_STRING="\"mute-indicator\"" - -# -D HAL_PCD_MODULE_ENABLED -# -D USB_PRODUCT=bluepill diff --git a/pkgs/mute-indicator/pulseaudio_mute_indicator/__init__.py b/pkgs/mute-indicator/pulseaudio_mute_indicator/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/pkgs/mute-indicator/pulseaudio_mute_indicator/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/pkgs/mute-indicator/pulseaudio_mute_indicator/service.py b/pkgs/mute-indicator/pulseaudio_mute_indicator/service.py deleted file mode 100644 index 0ef8e51..0000000 --- a/pkgs/mute-indicator/pulseaudio_mute_indicator/service.py +++ /dev/null @@ -1,28 +0,0 @@ -import pulsectl -import serial - - -def run(): - with pulsectl.Pulse("event-printer") as pulse: - - def print_events(ev): - with pulsectl.Pulse("event-source-info") as pulse2: - source = pulse2.source_info(ev.index) - if source.name in [ - "alsa_input.usb-BEHRINGER_UMC202HD_192k-00.analog-stereo", - "alsa_input.usb-BEHRINGER_UMC202HD_192k-00.analog-stereo-input", - ]: - muted = bool(source.mute) - with serial.Serial(port="/dev/mute-indicator", baudrate=115200) as ser: - if muted: - ser.write("L0:32,0,0\n".encode()) - ser.write("L1:32,0,0\n".encode()) - ser.write("S\n".encode()) - else: - ser.write("L0:0,32,0\n".encode()) - ser.write("L1:0,32,0\n".encode()) - ser.write("S\n".encode()) - - pulse.event_mask_set("source") - pulse.event_callback_set(print_events) - pulse.event_listen(timeout=0) diff --git a/pkgs/mute-indicator/setup.py b/pkgs/mute-indicator/setup.py deleted file mode 100644 index 742c390..0000000 --- a/pkgs/mute-indicator/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -from setuptools import setup, find_packages - -setup( - name="pulseaudio_mute_indicator", - version="0.0.1", - url="https://github.com/jalr/mute-indicator.git", - author="jalr", - author_email="mail@jalr.de", - description="Microphone mute LED indicator", - packages=find_packages(), - install_requires=[ - "pulsectl", - "pyserial", - ], - entry_points={ - "console_scripts": [ - "mute-indicator-service = pulseaudio_mute_indicator.service:run", - ], - }, -) diff --git a/pkgs/mute-indicator/src/main.cpp b/pkgs/mute-indicator/src/main.cpp deleted file mode 100644 index 5f9ec6b..0000000 --- a/pkgs/mute-indicator/src/main.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -#define NUM_LEDS 2 -#define DATA_PIN PB8 - -Adafruit_NeoPixel pixels(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800); - -void setup() { - Serial.begin(115200); - delay(500); - pixels.begin(); - Serial.println("Serial Neopixel interface ready."); - pixels.clear(); -} - -void loop() { - if (Serial.available() > 0) { - Serial.println("Received command"); - char command = Serial.read(); - switch(command) { - case 'L': - { - Serial.println("got L"); - String ledStr = Serial.readStringUntil(':'); - if (ledStr.length() > 0) { - long led = ledStr.toInt(); - Serial.print("got led:"); - Serial.println(led); - long red = Serial.readStringUntil(',').toInt(); - Serial.print("got red:"); - Serial.println(red); - long green = Serial.readStringUntil(',').toInt(); - Serial.print("got green:"); - Serial.println(green); - long blue = Serial.readStringUntil('\n').toInt(); - Serial.print("got blue:"); - Serial.println(blue); - pixels.setPixelColor(led, pixels.Color(red, green, blue)); - Serial.println("pixel set."); - } - break; - } - case 'S': - { - Serial.readStringUntil('\n'); - pixels.show(); - Serial.println("pixel shown."); - break; - } - case 'C': - { - Serial.readStringUntil('\n'); - pixels.clear(); - Serial.println("pixels cleared."); - break; - } - } - } -} diff --git a/users/jalr/modules/default.nix b/users/jalr/modules/default.nix index f97916b..3b79c49 100644 --- a/users/jalr/modules/default.nix +++ b/users/jalr/modules/default.nix @@ -24,7 +24,6 @@ ./lsd ./mixxc ./mpv.nix - ./mute-indicator.nix ./mycli ./neovim ./nix-index.nix diff --git a/users/jalr/modules/mute-indicator.nix b/users/jalr/modules/mute-indicator.nix deleted file mode 100644 index ecde0cd..0000000 --- a/users/jalr/modules/mute-indicator.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ nixosConfig, lib, pkgs, ... }: - -lib.mkIf nixosConfig.jalr.gui.enable { - home.packages = with pkgs; [ - mute-indicator - ]; - - systemd.user.services.mute-indicator = { - Unit.Description = "Mute Indicator"; - Service = { - Type = "simple"; - ExecStart = "${pkgs.mute-indicator}/bin/mute-indicator-service"; - RestartSec = 5; - Restart = "on-failure"; - }; - Install.WantedBy = [ "default.target" ]; - }; -} From 7628721799ba2415df019279582d4b1546d7b10e Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 00:07:56 +0100 Subject: [PATCH 11/33] Fix removed option definitions --- modules/mailserver/postfix.nix | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/mailserver/postfix.nix b/modules/mailserver/postfix.nix index e813dcb..1bd0079 100644 --- a/modules/mailserver/postfix.nix +++ b/modules/mailserver/postfix.nix @@ -45,8 +45,11 @@ lib.mkIf cfg.enable { hostname = cfg.fqdn; networksStyle = "host"; - sslCert = "${cfg.certDir}/fullchain.pem"; - sslKey = "${cfg.certDir}/key.pem"; + + settings.main.smtpd_tls_chain_files = [ + "${cfg.certDir}/key.pem" + "${cfg.certDir}/fullchain.pem" + ]; recipientDelimiter = "+"; From 9c9e0b4a86e186a8a616898f09e4282050c87419 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 00:33:42 +0100 Subject: [PATCH 12/33] Rename dnscrypt-proxy The option `services.dnscrypt-proxy2` has been renamed to `services.dnscrypt-proxy` --- modules/dns.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/dns.nix b/modules/dns.nix index a15d066..9acae6b 100644 --- a/modules/dns.nix +++ b/modules/dns.nix @@ -6,7 +6,7 @@ let in { config = lib.mkIf config.jalr.workstation.enable { - services.dnscrypt-proxy2 = { + services.dnscrypt-proxy = { enable = true; settings = { ipv6_servers = true; From 65e2a3e9f162f8a1863dc053cce1a4372d4d939c Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 00:36:09 +0100 Subject: [PATCH 13/33] Rename utillinux package 'utillinux' has been renamed to/replaced by 'util-linux' --- modules/autologin.nix | 2 +- users/jalr/modules/sway/waybar.nix | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/autologin.nix b/modules/autologin.nix index b0b4576..db0409f 100644 --- a/modules/autologin.nix +++ b/modules/autologin.nix @@ -27,7 +27,7 @@ in serviceConfig = lib.mkForce { ExecStart = [ "" # override upstream default with an empty ExecStart - "@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login --autologin '${cfg.autologin.username}' --noclear %I $TERM" + "@${pkgs.util-linux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login --autologin '${cfg.autologin.username}' --noclear %I $TERM" ]; restartIfChanged = false; }; diff --git a/users/jalr/modules/sway/waybar.nix b/users/jalr/modules/sway/waybar.nix index c507ce9..33607f5 100644 --- a/users/jalr/modules/sway/waybar.nix +++ b/users/jalr/modules/sway/waybar.nix @@ -430,7 +430,7 @@ in # ensure sway is already started, otherwise workspaces will not work ExecStartPre = "${config.wayland.windowManager.sway.package}/bin/swaymsg"; ExecStart = "${pkgs.waybar}/bin/waybar"; - ExecReload = "${pkgs.utillinux}/bin/kill -SIGUSR2 $MAINPID"; + ExecReload = "${pkgs.util-linux}/bin/kill -SIGUSR2 $MAINPID"; Restart = "on-failure"; RestartSec = "1s"; }; From b9e326dfe42406611e4ae9daa505f78a3a25154e Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 10:01:57 +0100 Subject: [PATCH 14/33] Adjust snapserver config to work with 25.05 --- hosts/iron/services/snapcast/snapserver.nix | 62 ++++++++------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/hosts/iron/services/snapcast/snapserver.nix b/hosts/iron/services/snapcast/snapserver.nix index 0d44d04..385c600 100644 --- a/hosts/iron/services/snapcast/snapserver.nix +++ b/hosts/iron/services/snapcast/snapserver.nix @@ -1,46 +1,30 @@ -{ lib, pkgs, config, ... }: +{ pkgs, config, ... }: let inherit (config.networking) ports; interfaces = import ../../interfaces.nix; + cfg = config.services.snapserver; + airplayPort1 = 5000; in { services.snapserver = { enable = true; - port = ports.snapserver.tcp; - tcp.port = ports.snapserverTcp.tcp; - http.port = ports.snapserverHttp.tcp; - streams = { - default = { - type = "meta"; - location = "meta:///hass/bluetooth/airplay/mopidy"; - query = { - chunk_ms = "30"; - buffer = "690"; - codec = "flac"; - }; + settings = { + tcp-streaming.port = ports.snapserver.tcp; + tcp = { + enabled = true; + port = ports.snapserverTcp.tcp; }; - mopidy = { - type = "pipe"; - location = "/run/snapserver/mopidy.fifo"; - }; - hass = { - type = "pipe"; - location = "/run/snapserver/hass.fifo"; - }; - bluetooth = { - location = ""; - type = "alsa"; - query = { - device = "hw:bluetooth,1"; - }; - }; - airplay = { - type = "airplay"; - location = lib.getExe' pkgs.shairport-sync "shairport-sync"; - query = { - devicename = "Snapcast"; - }; + http = { + enabled = true; + port = ports.snapserverHttp.tcp; }; + stream.source = [ + "airplay://${pkgs.shairport-sync}/bin/shairport-sync?name=airplay&devicename=Snapcast&port=${toString airplayPort1}" + #"alsa://?name=bluetooth&device=hw:bluetooth,1" + "pipe:///run/snapserver/hass.fifo?name=hass" + "pipe:///run/snapserver/mopidy.fifo?name=mopidy" + "meta:///hass/airplay/mopidy?name=default&buffer=690&chunk_ms=30&codec=flac" + ]; }; }; @@ -55,10 +39,10 @@ in networking.firewall.interfaces."${interfaces.lan}" = { allowedTCPPorts = [ - config.services.snapserver.http.port - config.services.snapserver.port - config.services.snapserver.tcp.port - 5000 # airplay + cfg.settings.http.port + cfg.settings.tcp.port + cfg.settings.tcp-streaming.port + airplayPort1 ]; allowedUDPPortRanges = [ { from = 6001; to = 6011; } # airplay @@ -67,7 +51,7 @@ in networking.firewall.interfaces.iot = { allowedTCPPorts = [ - config.services.snapserver.port + cfg.settings.stream.port ]; }; } From 5c0810e7251c4bf9d9d0e486221904ceefbe67b0 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 10:50:34 +0100 Subject: [PATCH 15/33] Migrate lsp config --- users/jalr/modules/neovim/default.nix | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/users/jalr/modules/neovim/default.nix b/users/jalr/modules/neovim/default.nix index 03b8b0b..34c091c 100644 --- a/users/jalr/modules/neovim/default.nix +++ b/users/jalr/modules/neovim/default.nix @@ -1,4 +1,4 @@ -{ lib, nixosConfig, config, pkgs, ... }: +{ lib, nixosConfig, pkgs, ... }: let fakePlugin = pkgs.runCommand "neovim-fake-plugin" { } "mkdir $out"; @@ -207,7 +207,6 @@ in '' -- this configuration applies to workstations only -- https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md - local lsp = require('lspconfig') -- show linter messages vim.diagnostic.config({ virtual_text = true }) @@ -215,7 +214,10 @@ in builtins.concatStringsSep "\n" ( lib.mapAttrsToList ( - lang: cfg: "lsp.${lang}.setup\n" + lib.generators.toLua { } cfg + lang: cfg: '' + vim.lsp.config('${lang}', ${lib.generators.toLua { } cfg}) + vim.lsp.enable('${lang}', true) + '' ) { # C and C++ From 37a8d355ee54f971dd398c6f4527536e07cad92c Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 18 Nov 2025 14:56:28 +0100 Subject: [PATCH 16/33] Replace sudo flag `--use-remote-sudo` is deprecated --- justfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/justfile b/justfile index d1d2a9a..bc38276 100644 --- a/justfile +++ b/justfile @@ -2,11 +2,11 @@ usb_ram_disk := "/dev/disk/by-label/RAM_USB" usb_ram_mountpoint := shell("findmnt -n -o TARGET $1 || true", usb_ram_disk) boot: - nixos-rebuild boot --flake . --use-remote-sudo + nixos-rebuild boot --flake . --sudo which fwupdmgr >/dev/null 2>&1 && fwupdmgr update || true switch: - nixos-rebuild switch --flake . --use-remote-sudo + nixos-rebuild switch --flake . --sudo which fwupdmgr >/dev/null 2>&1 && fwupdmgr update || true build: From a4bdad1880904a176cacf9cc336b698540369036 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 15:13:14 +0100 Subject: [PATCH 17/33] Bump version of vim-typoscript --- pkgs/vim-typoscript/default.nix | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/pkgs/vim-typoscript/default.nix b/pkgs/vim-typoscript/default.nix index ab85d79..dd90c89 100644 --- a/pkgs/vim-typoscript/default.nix +++ b/pkgs/vim-typoscript/default.nix @@ -1,12 +1,11 @@ -{ buildVimPlugin, fetchFromGitHub }: +{ buildVimPlugin, fetchgit }: buildVimPlugin rec { pname = "vim-typoscript"; - version = "2.0.0"; - src = fetchFromGitHub { - owner = "DanielSiepmann"; - repo = "mirror-vim.typoscript"; + version = "2.1.0"; + src = fetchgit { + url = "https://git.daniel-siepmann.de/danielsiepmann/vim-syntax-typoscript"; rev = "v${version}"; - sha256 = "sha256-fCB+ikDmkfEP/W0pFYGrsZiH30vT0g3z6GZpRGk0Rhc="; + hash = "sha256-m2Gxycsrs9WbPydXCziWFsIYMJrDlfGF98SaamPBuuM="; }; meta.homepage = "https://git.daniel-siepmann.de/danielsiepmann/vim-syntax-typoscript"; } From 36553d0cfca6c20dd1714dd04f2ceff7395ec71b Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 15:15:53 +0100 Subject: [PATCH 18/33] Bump tabbed-box-maker --- pkgs/tabbed-box-maker/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/tabbed-box-maker/default.nix b/pkgs/tabbed-box-maker/default.nix index dee949e..e327776 100644 --- a/pkgs/tabbed-box-maker/default.nix +++ b/pkgs/tabbed-box-maker/default.nix @@ -9,14 +9,14 @@ stdenvNoCC.mkDerivation { src = fetchFromGitHub { owner = "paulh-rnd"; repo = "TabbedBoxMaker"; - rev = "7df0e6c711aeef36b6a89e3f3fe456b09225c836"; + rev = "023dda4255b0a5b4e24196ed40fc956bd8394254"; fetchSubmodules = true; - sha256 = "8TNNVMSwbvcEwkvMHecHtGLEpiX3F0g0EGsgO1YKBGQ="; + sha256 = "sha256-wXZHg31HbOKHYxwgeoYUp2rMt4tdW4p9R3CEM69U1eU="; }; dontBuild = true; installPhase = '' mkdir $out - cp * $out + cp -r * $out ''; } From 3527a5e21dfe79b0fe66ee693a48b7a0793f4d5d Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 16:04:57 +0100 Subject: [PATCH 19/33] Bump version of docker-machine-driver-hetzner --- .../docker-machine-driver-hetzner/default.nix | 4 +- .../gomod2nix.toml | 51 +++++++++---------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/pkgs/docker-machine-driver-hetzner/default.nix b/pkgs/docker-machine-driver-hetzner/default.nix index aa0efa1..f3c9828 100644 --- a/pkgs/docker-machine-driver-hetzner/default.nix +++ b/pkgs/docker-machine-driver-hetzner/default.nix @@ -2,12 +2,12 @@ buildGoApplication rec { pname = "docker-machine-driver-hetzner"; - version = "5.0.1"; + version = "5.0.2"; src = fetchFromGitHub { rev = "${version}"; owner = "JonasProgrammer"; repo = "docker-machine-driver-hetzner"; - sha256 = "sha256-JREn6AzayaHkyhdOTJ8P2H/s/5RaKLe+Qb8GV5dI2pA="; + sha256 = "sha256-5mSlKedXSHNKnjfx+qVXplReSMZ5SKQBXt9Ct+ivgjk="; }; modules = ./gomod2nix.toml; #nativeBuildInputs = [ pkg-config ]; diff --git a/pkgs/docker-machine-driver-hetzner/gomod2nix.toml b/pkgs/docker-machine-driver-hetzner/gomod2nix.toml index d38264c..fc6567c 100644 --- a/pkgs/docker-machine-driver-hetzner/gomod2nix.toml +++ b/pkgs/docker-machine-driver-hetzner/gomod2nix.toml @@ -11,8 +11,8 @@ schema = 3 version = "v2.2.0" hash = "sha256-nPufwYQfTkyrEkbBrpqM3C2vnMxfIz6tAaBmiUP7vd4=" [mod."github.com/codegangsta/cli"] - version = "v1.22.12" - hash = "sha256-FTdBlhQvyDhgrDcSJDxgSLS/cBSP8B1BC/AxGA9Lyss=" + version = "v1.22.14" + hash = "sha256-lpNDP0bM02JWeUjCOXU8HwHk3FT5zB4gIOO/EvaxRao=" replaced = "github.com/urfave/cli" [mod."github.com/cpuguy83/go-md2man/v2"] version = "v2.0.2" @@ -27,47 +27,44 @@ schema = 3 version = "v1.5.3" hash = "sha256-svogITcP4orUIsJFjMtp+Uv1+fKJv2Q5Zwf2dMqnpOQ=" [mod."github.com/hetznercloud/hcloud-go/v2"] - version = "v2.2.0" - hash = "sha256-4sOfDyy/VP/LSoIm/ydtJKxKljtfLCC7ZzgWh9NPuAc=" + version = "v2.5.1" + hash = "sha256-SaYuQIdfI3S2+RM7bNE9wIPRnaKkv3giq8fOS671/KM=" [mod."github.com/matttproud/golang_protobuf_extensions"] version = "v1.0.4" hash = "sha256-uovu7OycdeZ2oYQ7FhVxLey5ZX3T0FzShaRldndyGvc=" [mod."github.com/moby/term"] version = "v0.0.0-20221205130635-1aeaba878587" hash = "sha256-wX2ftzjEHzltzN68CsYVXMiaLPNU7V2phVyyPKv3mn8=" - [mod."github.com/pkg/errors"] - version = "v0.9.1" - hash = "sha256-mNfQtcrQmu3sNg/7IwiieKWOgFQOVVe2yXgKBpe/wZw=" [mod."github.com/prometheus/client_golang"] - version = "v1.16.0" - hash = "sha256-P/b4/8m1ztF0fCLSJ+eRXN74Bncx2vjOJx7nFl2QEg4=" + version = "v1.17.0" + hash = "sha256-FIIzCuNqHdVzpbyH7yAp7Tcu+1tPxEMS5g6KfsGQBGE=" [mod."github.com/prometheus/client_model"] - version = "v0.3.0" - hash = "sha256-vP+miJfsoK5UG9eug8z/bhAMj3bwg66T2vIh8WHoOKU=" + version = "v0.4.1-0.20230718164431-9a2bf3000d16" + hash = "sha256-t9LgImRW4h0XMSxfAazrGHqyDljDyl0YC5r9cYuXcKc=" [mod."github.com/prometheus/common"] - version = "v0.42.0" - hash = "sha256-dJqoPZKtY2umWFWwMeRYY9I2JaFlpcMX4atkEcN5+hs=" + version = "v0.44.0" + hash = "sha256-8n3gSWKDSJtGfOQgxsiCGyTnUjb5hvSxJi/hPcrE5Oo=" [mod."github.com/prometheus/procfs"] - version = "v0.10.1" - hash = "sha256-EJ8q8wux4964WE4X7UkHb+MXjLhX4TROJaoLIQvD/eQ=" + version = "v0.11.1" + hash = "sha256-yphZ7NZtYC/tb0HVag2T58SuN64Ial9sBo/TdCEQx6Q=" [mod."github.com/russross/blackfriday/v2"] version = "v2.1.0" hash = "sha256-R+84l1si8az5yDqd5CYcFrTyNZ1eSYlpXKq6nFt4OTQ=" [mod."golang.org/x/crypto"] - version = "v0.12.0" - hash = "sha256-Wes72EA9ICTG8o0nEYWZk9xjpqlniorFeY6o26GExns=" + version = "v0.16.0" + hash = "sha256-DgSVOnXRK8GF01p5rLtq4qPBcglwEoOk8qhW2EGfJfA=" [mod."golang.org/x/net"] - version = "v0.12.0" - hash = "sha256-zQZBj42+wLLxXwS/e+KNbu8+SukMDxxW23WSi5XQXAA=" + version = "v0.19.0" + hash = "sha256-3M5rKEvJx4cO/q+06cGjR5sxF5JpnUWY0+fQttrWdT4=" [mod."golang.org/x/sys"] - version = "v0.11.0" - hash = "sha256-g/LjhABK2c/u6v7M2aAIrHvZjmx/ikGHkef86775N38=" + version = "v0.15.0" + hash = "sha256-n7TlABF6179RzGq3gctPDKDPRtDfnwPdjNCMm8ps2KY=" [mod."golang.org/x/term"] - version = "v0.11.0" - hash = "sha256-muSv/d8Qpl+NXiOB01n6LeFEzC+hrlGviDdfu+6QdQ4=" + version = "v0.15.0" + hash = "sha256-rsvtsE7sKmBwtR+mhJ8iUq93ZT8fV2LU+Pd69sh2es8=" [mod."golang.org/x/text"] - version = "v0.12.0" - hash = "sha256-aNQaW3EgCK9ehpnBzIAkZX6TmiUU1S175YlJUH7P5Qg=" + version = "v0.14.0" + hash = "sha256-yh3B0tom1RfzQBf1RNmfdNWF1PtiqxV41jW1GVS6JAg=" [mod."google.golang.org/protobuf"] - version = "v1.30.0" - hash = "sha256-Y07NKhSuJQ2w7F7MAINQyBf+/hdMHOrxwA3B4ljQQKs=" + version = "v1.31.0" + hash = "sha256-UdIk+xRaMfdhVICvKRk1THe3R1VU+lWD8hqoW/y8jT0=" From 027611ae7eab6a94cccac5754ea99541721e4b41 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 25 Nov 2025 16:25:32 +0100 Subject: [PATCH 20/33] Bump version of docker-machine-gitlab --- pkgs/docker-machine-gitlab/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/docker-machine-gitlab/default.nix b/pkgs/docker-machine-gitlab/default.nix index ca847bd..a6651ab 100644 --- a/pkgs/docker-machine-gitlab/default.nix +++ b/pkgs/docker-machine-gitlab/default.nix @@ -11,7 +11,7 @@ ( buildGoApplication rec { pname = "docker-machine-gitlab"; - version = "0.16.2-gitlab.32"; + version = "0.16.2-gitlab.42"; goPackagePath = "github.com/docker/machine"; modules = ./gomod2nix.toml; @@ -20,7 +20,7 @@ group = "gitlab-org"; owner = "ci-cd"; repo = "docker-machine"; - sha256 = "sha256-jipKo3LRTDUVKMkBK2qH/JIUcj3vJh7SdcQ8FMTr2Ok="; + sha256 = "sha256-cq36HK//sY7e+Vej7dbEXWymCzwMFXpztINJIqiiLyA="; }; nativeBuildInputs = [ From c53e73b6932fcc0d6bcba5f5a8a6027eb691afda Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Wed, 26 Nov 2025 11:38:54 +0100 Subject: [PATCH 21/33] Bump tree-style-tab version --- users/jalr/modules/firefox/default.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/users/jalr/modules/firefox/default.nix b/users/jalr/modules/firefox/default.nix index 62b3eb5..9f708c5 100644 --- a/users/jalr/modules/firefox/default.nix +++ b/users/jalr/modules/firefox/default.nix @@ -277,9 +277,9 @@ darkreader sponsorblock (tree-style-tab.override { - version = "4.1.6"; - url = "https://addons.mozilla.org/firefox/downloads/file/4488104/tree_style_tab-4.1.6.xpi"; - sha256 = "sha256-X0HC6jzytjBsM+8HmbK48DUihtdN9oCsqLUJqp29csQ="; + version = "4.1.11"; + url = "https://addons.mozilla.org/firefox/downloads/file/4502732/tree_style_tab-4.1.11.xpi"; + sha256 = "sha256-6TFKdnO8I5vls6b75Ig633ffabXIAbiVQa9QuPADfvU="; }) ublock-origin umatrix From 784e4e873793924b07a66abccf0aab131a5e21bb Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 1 Dec 2025 15:21:15 +0100 Subject: [PATCH 22/33] Update stateVersion --- hosts/aluminium/configuration.nix | 9 +-------- hosts/cadmium/configuration.nix | 9 +-------- hosts/copper/configuration.nix | 2 +- hosts/iron/configuration.nix | 2 +- hosts/jalr-t520/configuration.nix | 2 +- hosts/magnesium/configuration.nix | 2 +- 6 files changed, 6 insertions(+), 20 deletions(-) diff --git a/hosts/aluminium/configuration.nix b/hosts/aluminium/configuration.nix index 3dfd6a3..e2105f6 100644 --- a/hosts/aluminium/configuration.nix +++ b/hosts/aluminium/configuration.nix @@ -130,13 +130,6 @@ priority = 1; }; - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "23.11"; # Did you read the comment? - + system.stateVersion = "25.11"; } diff --git a/hosts/cadmium/configuration.nix b/hosts/cadmium/configuration.nix index 32c1151..9d91380 100644 --- a/hosts/cadmium/configuration.nix +++ b/hosts/cadmium/configuration.nix @@ -57,12 +57,5 @@ autologin.username = "jalr"; }; - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "23.11"; # Did you read the comment? - + system.stateVersion = "25.11"; } diff --git a/hosts/copper/configuration.nix b/hosts/copper/configuration.nix index 841d390..bb38116 100644 --- a/hosts/copper/configuration.nix +++ b/hosts/copper/configuration.nix @@ -72,6 +72,6 @@ }; }; - system.stateVersion = "24.05"; + system.stateVersion = "25.11"; } diff --git a/hosts/iron/configuration.nix b/hosts/iron/configuration.nix index 57a422a..19eeef1 100644 --- a/hosts/iron/configuration.nix +++ b/hosts/iron/configuration.nix @@ -37,7 +37,7 @@ with lib; { ./ports.nix ]; config = { - system.stateVersion = "25.05"; + system.stateVersion = "25.11"; security.sudo.wheelNeedsPassword = false; diff --git a/hosts/jalr-t520/configuration.nix b/hosts/jalr-t520/configuration.nix index e10957b..c273842 100644 --- a/hosts/jalr-t520/configuration.nix +++ b/hosts/jalr-t520/configuration.nix @@ -38,5 +38,5 @@ hardware.graphics.extraPackages = lib.singleton pkgs.vaapiIntel; - system.stateVersion = "25.05"; + system.stateVersion = "25.11"; } diff --git a/hosts/magnesium/configuration.nix b/hosts/magnesium/configuration.nix index 626f0b8..5b27a65 100644 --- a/hosts/magnesium/configuration.nix +++ b/hosts/magnesium/configuration.nix @@ -28,5 +28,5 @@ priority = 1; }; - system.stateVersion = "24.11"; + system.stateVersion = "25.11"; } From 6d26621417d204eefc246dec682354c741dd0936 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 8 Dec 2025 16:21:17 +0100 Subject: [PATCH 23/33] Remove default headers to be able to use different values for these headers in different virtual hosts. --- hosts/magnesium/services/webserver.nix | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hosts/magnesium/services/webserver.nix b/hosts/magnesium/services/webserver.nix index a30a098..480048f 100644 --- a/hosts/magnesium/services/webserver.nix +++ b/hosts/magnesium/services/webserver.nix @@ -20,10 +20,6 @@ in https "max-age=31536000"; } add_header Strict-Transport-Security $hsts_header; - - add_header Referrer-Policy strict-origin; - add_header X-Content-Type-Options nosniff; - add_header X-Frame-Options SAMEORIGIN; ''; virtualHosts = { "${domain}" = { From 3dc4f456cc605a897c4061bfd2cacaed346d8520 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Thu, 4 Dec 2025 16:44:55 +0100 Subject: [PATCH 24/33] Add IP service --- hosts/magnesium/services/default.nix | 1 + hosts/magnesium/services/ip.nix | 64 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 hosts/magnesium/services/ip.nix diff --git a/hosts/magnesium/services/default.nix b/hosts/magnesium/services/default.nix index c257730..6ee1681 100644 --- a/hosts/magnesium/services/default.nix +++ b/hosts/magnesium/services/default.nix @@ -4,6 +4,7 @@ ./forgejo.nix ./gitlab-runner.nix ./hedgedoc.nix + ./ip.nix ./it-tools.nix ./mealie.nix ./ntfy.nix diff --git a/hosts/magnesium/services/ip.nix b/hosts/magnesium/services/ip.nix new file mode 100644 index 0000000..a18a531 --- /dev/null +++ b/hosts/magnesium/services/ip.nix @@ -0,0 +1,64 @@ +{ pkgs, lib, ... }: + +let + baseDomain = "jalr.de"; + webDomain = "ip.${baseDomain}"; + ip4Domain = "ip4.${baseDomain}"; + ip6Domain = "ip6.${baseDomain}"; +in +{ + services.nginx.virtualHosts = lib.attrsets.genAttrs [ ip4Domain ip6Domain ] + (_: { + enableACME = true; + addSSL = true; + locations."/" = { + return = ''200 "$remote_addr\n"''; + extraConfig = '' + types { } default_type "text/plain; charset=utf-8"; + add_header Access-Control-Allow-Origin *; + ''; + }; + }) // { + "${webDomain}" = { + enableACME = true; + forceSSL = true; + root = pkgs.writeTextDir "index.html" '' + + + + ${webDomain} + + +

${webDomain}

+
    +
  • IPv6: Loading...
  • +
  • IPv4: Loading...
  • +
+ + + + ''; + }; + }; +} From e0ea85dcde327b3c98a8023fe62d4b384b11c350 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 8 Dec 2025 15:21:51 +0100 Subject: [PATCH 25/33] Migrate mailserver config to 25.11 --- hosts/iron/services/mail.nix | 24 +++--- modules/mailserver/default.nix | 5 -- modules/mailserver/dovecot.nix | 57 +++++++------- modules/mailserver/postfix.nix | 133 ++++++++++++++++----------------- 4 files changed, 102 insertions(+), 117 deletions(-) diff --git a/hosts/iron/services/mail.nix b/hosts/iron/services/mail.nix index c5d855e..9040449 100644 --- a/hosts/iron/services/mail.nix +++ b/hosts/iron/services/mail.nix @@ -1,15 +1,9 @@ -{ config, ... }: - -let - inherit (config.networking) ports; -in { #sops.secrets."domain_key_jalr.de".owner = "rspamd"; jalr = { mailserver = { enable = true; fqdn = "hha.jalr.de"; - relayPort = ports.postfix-relay.tcp; domains = [ { domain = "jalr.de"; @@ -25,14 +19,18 @@ in }; }; services.postfix = { - config = { - smtp_bind_address = "159.69.103.126"; - smtp_bind_address_enforce = true; + settings = { + main = { + smtp_bind_address = "159.69.103.126"; + smtp_bind_address_enforce = true; + }; + master = { + smtp.args = [ + "-o" + "inet_protocols=ipv4" + ]; + }; }; - masterConfig.smtp.args = [ - "-o" - "inet_protocols=ipv4" - ]; }; services.nginx.virtualHosts."hha.jalr.de" = { enableACME = true; diff --git a/modules/mailserver/default.nix b/modules/mailserver/default.nix index 59a8e2c..a18dc19 100644 --- a/modules/mailserver/default.nix +++ b/modules/mailserver/default.nix @@ -5,11 +5,6 @@ in { options.jalr.mailserver = with lib; with lib.types; { enable = mkEnableOption "simple mail server"; - relayPort = mkOption { - description = "SMTP port for relay mail relay."; - type = port; - default = 25; - }; fqdn = mkOption { type = str; description = '' diff --git a/modules/mailserver/dovecot.nix b/modules/mailserver/dovecot.nix index a2485a5..dbd6e71 100644 --- a/modules/mailserver/dovecot.nix +++ b/modules/mailserver/dovecot.nix @@ -8,6 +8,26 @@ let "\n" ({ address, passwordHash, ... }: "${address}:${passwordHash}") cfg.users); + + sieveScripts = { + learn-spam = pkgs.writeText "learn-spam.sieve" '' + require ["vnd.dovecot.pipe", "copy", "imapsieve"]; + pipe :copy "rspamc" ["learn_spam"]; + ''; + learn-ham = pkgs.writeText "learn-ham.sieve" '' + require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; + + if environment :matches "imap.mailbox" "*" { + set "mailbox" "''${1}"; + } + + if string "''${mailbox}" "Trash" { + stop; + } + + pipe :copy "rspamc" ["learn_ham"]; + ''; + }; in lib.mkIf cfg.enable { services.dovecot2 = { @@ -111,12 +131,12 @@ lib.mkIf cfg.enable { ${lib.optionalString cfg.spam.enable '' imapsieve_mailbox1_name = Spam imapsieve_mailbox1_causes = COPY - imapsieve_mailbox1_before = file:/var/lib/dovecot/sieve/learn-spam.sieve + imapsieve_mailbox1_before = file:${sieveScripts.learn-spam} imapsieve_mailbox2_name = * imapsieve_mailbox2_from = Spam imapsieve_mailbox2_causes = COPY - imapsieve_mailbox2_before = file:/var/lib/dovecot/sieve/learn-ham.sieve + imapsieve_mailbox2_before = file:${sieveScripts.learn-ham} sieve_pipe_bin_dir = ${pkgs.symlinkJoin { name = "sieve-pipe-bin-dir"; paths = with pkgs; [ rspamd ]; } }/bin ''} } @@ -125,37 +145,12 @@ lib.mkIf cfg.enable { environment.systemPackages = [ pkgs.dovecot_pigeonhole ]; - systemd.services.dovecot2 = { + /* + systemd.services.dovecot2 = { wants = [ "acme-finished-${cfg.fqdn}.target" ]; after = [ "acme-finished-${cfg.fqdn}.target" ]; - - preStart = lib.mkIf cfg.spam.enable - (lib.mkAfter - (lib.concatStrings - (lib.mapAttrsToList - (name: content: '' - cp ${pkgs.writeText name content} /var/lib/dovecot/sieve/${name} - '') - { - "learn-spam.sieve" = '' - require ["vnd.dovecot.pipe", "copy", "imapsieve"]; - pipe :copy "rspamc" ["learn_spam"]; - ''; - "learn-ham.sieve" = '' - require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"]; - - if environment :matches "imap.mailbox" "*" { - set "mailbox" "''${1}"; - } - - if string "''${mailbox}" "Trash" { - stop; - } - - pipe :copy "rspamc" ["learn_ham"]; - ''; - }))); - }; + }; + */ networking.firewall.allowedTCPPorts = [ 143 # IMAP diff --git a/modules/mailserver/postfix.nix b/modules/mailserver/postfix.nix index 1bd0079..1209fb0 100644 --- a/modules/mailserver/postfix.nix +++ b/modules/mailserver/postfix.nix @@ -38,75 +38,81 @@ lib.mkIf cfg.enable { services.postfix = { enable = true; - inherit (cfg) relayPort; - enableSubmission = false; # plain/STARTTLS (latter is forced in submissionOptions) enableSubmissions = true; # submission with implicit TLS (TCP/465) - hostname = cfg.fqdn; - networksStyle = "host"; + settings = { + main = { + smtpd_tls_chain_files = [ + "${cfg.certDir}/key.pem" + "${cfg.certDir}/fullchain.pem" + ]; + recipient_delimiter = "+"; + myhostname = cfg.fqdn; + mynetworks_style = "host"; - settings.main.smtpd_tls_chain_files = [ - "${cfg.certDir}/key.pem" - "${cfg.certDir}/fullchain.pem" - ]; + # General + smtpd_banner = "${cfg.fqdn} ESMTP"; + disable_vrfy_command = true; # disable check if mailbox exists + enable_long_queue_ids = true; # better for debugging + strict_rfc821_envelopes = true; # only accept properly formatted envelope + message_size_limit = cfg.messageSizeLimit; - recipientDelimiter = "+"; + virtual_mailbox_domains = listToString (map (x: x.domain) cfg.domains); + virtual_mailbox_maps = "hash:/var/lib/postfix/conf/valiases"; + virtual_alias_maps = "hash:/var/lib/postfix/conf/valiases"; + virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp"; + + smtpd_recipient_restrictions = listToString [ + "reject_non_fqdn_recipient" + "reject_unknown_recipient_domain" + "reject_unverified_recipient" + ]; + + smtpd_client_restrictions = listToString [ + "reject_unknown_client_hostname" + ]; + + smtpd_sender_restrictions = listToString [ + "reject_non_fqdn_sender" + "reject_unknown_sender_domain" + ]; + + # generated 2021-02-04, Mozilla Guideline v5.6, Postfix 3.5.6, OpenSSL 1.1.1i, intermediate configuration + # https://ssl-config.mozilla.org/#server=postfix&version=3.5.6&config=intermediate&openssl=1.1.1i&guideline=5.6 + smtpd_tls_security_level = "may"; + smtpd_tls_auth_only = "yes"; + smtpd_tls_mandatory_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1"; + smtpd_tls_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1"; + smtpd_tls_mandatory_ciphers = "medium"; + smtpd_tls_loglevel = "1"; + + tls_medium_cipherlist = listToString [ + "ECDHE-ECDSA-AES128-GCM-SHA256" + "ECDHE-RSA-AES128-GCM-SHA256" + "ECDHE-ECDSA-AES256-GCM-SHA384" + "ECDHE-RSA-AES256-GCM-SHA384" + "ECDHE-ECDSA-CHACHA20-POLY1305" + "ECDHE-RSA-CHACHA20-POLY1305" + "DHE-RSA-AES128-GCM-SHA256" + "DHE-RSA-AES256-GCM-SHA384" + ]; + tls_preempt_cipherlist = "no"; + }; + master = { + submission-header-cleanup = { + private = false; + maxproc = 0; + command = "cleanup"; + args = [ "-o" "header_checks=pcre:${submissionHeaderCleanupRules}" ]; + }; + }; + }; mapFiles = { inherit valiases; }; - config = { - # General - smtpd_banner = "${cfg.fqdn} ESMTP"; - disable_vrfy_command = true; # disable check if mailbox exists - enable_long_queue_ids = true; # better for debugging - strict_rfc821_envelopes = true; # only accept properly formatted envelope - message_size_limit = toString cfg.messageSizeLimit; - - virtual_mailbox_domains = listToString (map (x: x.domain) cfg.domains); - virtual_mailbox_maps = "hash:/var/lib/postfix/conf/valiases"; - virtual_alias_maps = "hash:/var/lib/postfix/conf/valiases"; - virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp"; - - smtpd_recipient_restrictions = listToString [ - "reject_non_fqdn_recipient" - "reject_unknown_recipient_domain" - "reject_unverified_recipient" - ]; - - smtpd_client_restrictions = listToString [ - "reject_unknown_client_hostname" - ]; - - smtpd_sender_restrictions = listToString [ - "reject_non_fqdn_sender" - "reject_unknown_sender_domain" - ]; - - # generated 2021-02-04, Mozilla Guideline v5.6, Postfix 3.5.6, OpenSSL 1.1.1i, intermediate configuration - # https://ssl-config.mozilla.org/#server=postfix&version=3.5.6&config=intermediate&openssl=1.1.1i&guideline=5.6 - smtpd_tls_security_level = "may"; - smtpd_tls_auth_only = "yes"; - smtpd_tls_mandatory_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1"; - smtpd_tls_protocols = "!SSLv2, !SSLv3, !TLSv1, !TLSv1.1"; - smtpd_tls_mandatory_ciphers = "medium"; - smtpd_tls_loglevel = "1"; - - tls_medium_cipherlist = listToString [ - "ECDHE-ECDSA-AES128-GCM-SHA256" - "ECDHE-RSA-AES128-GCM-SHA256" - "ECDHE-ECDSA-AES256-GCM-SHA384" - "ECDHE-RSA-AES256-GCM-SHA384" - "ECDHE-ECDSA-CHACHA20-POLY1305" - "ECDHE-RSA-CHACHA20-POLY1305" - "DHE-RSA-AES128-GCM-SHA256" - "DHE-RSA-AES256-GCM-SHA384" - ]; - tls_preempt_cipherlist = "no"; - }; - # plain/STARTTLS (forced with smtpd_tls_security_level) submissionOptions = { smtpd_tls_security_level = "encrypt"; @@ -132,15 +138,6 @@ lib.mkIf cfg.enable { }; # implicit TLS submissionsOptions = config.services.postfix.submissionOptions; - - masterConfig = { - submission-header-cleanup = { - private = false; - maxproc = 0; - command = "cleanup"; - args = [ "-o" "header_checks=pcre:${submissionHeaderCleanupRules}" ]; - }; - }; }; networking.firewall.allowedTCPPorts = [ From 430b1f01d2c077a8868ca2e09ae686560d8d3265 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 8 Dec 2025 16:22:25 +0100 Subject: [PATCH 26/33] Update mopidy config to 25.11 --- hosts/iron/services/snapcast/mopidy.nix | 64 ++++++++++++------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/hosts/iron/services/snapcast/mopidy.nix b/hosts/iron/services/snapcast/mopidy.nix index 18be1a5..fead046 100644 --- a/hosts/iron/services/snapcast/mopidy.nix +++ b/hosts/iron/services/snapcast/mopidy.nix @@ -1,35 +1,7 @@ { lib, pkgs, config, ... }: let interfaces = import ../../interfaces.nix; - mopidyConfig = { - audio.output = "audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/run/snapserver/mopidy.fifo"; - file.enabled = false; - local = { - library = "sqlite"; - scan_flush_threshold = 100; - media_dir = "/var/lib/music"; - included_file_extensions = lib.strings.concatStringsSep "," [ - ".aac" - ".flac" - ".m4a" - ".mp3" - ".opus" - ]; - }; - m3u = { - playlists_dir = "$XDG_CONFIG_DIR/mopidy/playlists"; - }; - http = { - enabled = true; - hostname = "::"; - port = 6680; - }; - mpd = { - enabled = true; - hostname = "::"; - port = 6600; - }; - }; + cfg = config.services.mopidy; in { services.mopidy = { @@ -43,12 +15,40 @@ in mopidy-somafm mopidy-ytmusic ]; - configuration = lib.generators.toINI { } mopidyConfig; + settings = { + audio.output = "audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/run/snapserver/mopidy.fifo"; + file.enabled = false; + local = { + library = "sqlite"; + scan_flush_threshold = 100; + media_dir = "/var/lib/music"; + included_file_extensions = lib.strings.concatStringsSep "," [ + ".aac" + ".flac" + ".m4a" + ".mp3" + ".opus" + ]; + }; + m3u = { + playlists_dir = "$XDG_CONFIG_DIR/mopidy/playlists"; + }; + http = { + enabled = true; + hostname = "::"; + port = 6680; + }; + mpd = { + enabled = true; + hostname = "::"; + port = 6600; + }; + }; }; networking.firewall.interfaces."${interfaces.lan}".allowedTCPPorts = [ - mopidyConfig.http.port - mopidyConfig.mpd.port + cfg.settings.http.port + cfg.settings.mpd.port ]; environment.systemPackages = [ From 611502e5bb9e095b23ecaf75a0da1351cae4844d Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 8 Dec 2025 16:25:02 +0100 Subject: [PATCH 27/33] Revert "Add BLE sniffer to Wireshark" This reverts commit 9dafacebda649da986892c6adca31a907b6138bd. --- modules/default.nix | 2 +- modules/wireshark.nix | 7 + modules/wireshark/default.nix | 23 - .../extcap/SnifferAPI/CaptureFiles.py | 91 -- .../wireshark/extcap/SnifferAPI/Devices.py | 150 --- .../wireshark/extcap/SnifferAPI/Exceptions.py | 66 -- .../wireshark/extcap/SnifferAPI/Filelock.py | 67 -- modules/wireshark/extcap/SnifferAPI/Logger.py | 214 ---- .../extcap/SnifferAPI/Notifications.py | 92 -- modules/wireshark/extcap/SnifferAPI/Packet.py | 651 ------------ modules/wireshark/extcap/SnifferAPI/Pcap.py | 82 -- .../wireshark/extcap/SnifferAPI/Sniffer.py | 270 ----- .../extcap/SnifferAPI/SnifferCollector.py | 326 ------ modules/wireshark/extcap/SnifferAPI/Types.py | 90 -- modules/wireshark/extcap/SnifferAPI/UART.py | 238 ----- .../wireshark/extcap/SnifferAPI/__init__.py | 0 .../wireshark/extcap/SnifferAPI/version.py | 37 - modules/wireshark/extcap/nrf_sniffer_ble.py | 991 ------------------ 18 files changed, 8 insertions(+), 3389 deletions(-) create mode 100644 modules/wireshark.nix delete mode 100644 modules/wireshark/default.nix delete mode 100644 modules/wireshark/extcap/SnifferAPI/CaptureFiles.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Devices.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Exceptions.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Filelock.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Logger.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Notifications.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Packet.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Pcap.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Sniffer.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/SnifferCollector.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/Types.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/UART.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/__init__.py delete mode 100644 modules/wireshark/extcap/SnifferAPI/version.py delete mode 100644 modules/wireshark/extcap/nrf_sniffer_ble.py diff --git a/modules/default.nix b/modules/default.nix index 38dc354..d2f35d2 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -49,7 +49,7 @@ ./uefi.nix ./unfree.nix ./upgrade-diff.nix - ./wireshark + ./wireshark.nix ./yubikey-gpg.nix ]; diff --git a/modules/wireshark.nix b/modules/wireshark.nix new file mode 100644 index 0000000..878f649 --- /dev/null +++ b/modules/wireshark.nix @@ -0,0 +1,7 @@ +{ config, lib, pkgs, ... }: +lib.mkIf config.jalr.gui.enable { + programs.wireshark = { + enable = true; + package = pkgs.wireshark; + }; +} diff --git a/modules/wireshark/default.nix b/modules/wireshark/default.nix deleted file mode 100644 index 6c1b0c0..0000000 --- a/modules/wireshark/default.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, lib, pkgs, ... }: -let - extcap = ./extcap; - pythonWithPackages = pkgs.python3.withPackages (pp: with pp; [ - pyserial - psutil - ]); - nrf_sniffer_ble = pkgs.writeShellScript "nrf_sniffer_ble" '' - script_path=$(dirname `which $0`) - - exec ${pythonWithPackages}/bin/python3 $script_path/nrf_sniffer_ble.py "$@" - ''; -in -lib.mkIf config.jalr.gui.enable { - programs.wireshark = { - enable = true; - package = pkgs.wireshark.overrideAttrs (o: { - postInstall = '' - cp -r ${extcap}/* ${nrf_sniffer_ble} $out/lib/wireshark/extcap - '' + o.postInstall; - }); - }; -} diff --git a/modules/wireshark/extcap/SnifferAPI/CaptureFiles.py b/modules/wireshark/extcap/SnifferAPI/CaptureFiles.py deleted file mode 100644 index 8c218e5..0000000 --- a/modules/wireshark/extcap/SnifferAPI/CaptureFiles.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -import time, os, logging -from . import Logger -from . import Pcap - - -DEFAULT_CAPTURE_FILE_DIR = Logger.DEFAULT_LOG_FILE_DIR -DEFAULT_CAPTURE_FILE_NAME = "capture.pcap" - - -def get_capture_file_path(capture_file_path=None): - default_path = os.path.join(DEFAULT_CAPTURE_FILE_DIR, DEFAULT_CAPTURE_FILE_NAME) - if capture_file_path is None: - return default_path - if os.path.splitext(capture_file_path)[1] != ".pcap": - return default_path - return os.path.abspath(capture_file_path) - - -class CaptureFileHandler: - def __init__(self, capture_file_path=None, clear=False): - filename = get_capture_file_path(capture_file_path) - if not os.path.isdir(os.path.dirname(filename)): - os.makedirs(os.path.dirname(filename)) - self.filename = filename - self.backupFilename = self.filename + ".1" - if not os.path.isfile(self.filename): - self.startNewFile() - elif os.path.getsize(self.filename) > 20000000: - self.doRollover() - if clear: - # clear file - self.startNewFile() - - def startNewFile(self): - with open(self.filename, "wb") as f: - f.write(Pcap.get_global_header()) - - def doRollover(self): - try: - os.remove(self.backupFilename) - except: - logging.exception("capture file rollover remove backup failed") - try: - os.rename(self.filename, self.backupFilename) - self.startNewFile() - except: - logging.exception("capture file rollover failed") - - def writePacket(self, packet): - with open(self.filename, "ab") as f: - packet = Pcap.create_packet( - bytes([packet.boardId] + packet.getList()), packet.time - ) - f.write(packet) diff --git a/modules/wireshark/extcap/SnifferAPI/Devices.py b/modules/wireshark/extcap/SnifferAPI/Devices.py deleted file mode 100644 index 61ac961..0000000 --- a/modules/wireshark/extcap/SnifferAPI/Devices.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright (c) 2017, Nordic Semiconductor ASA -# -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from . import Notifications -import logging, threading - - -class DeviceList(Notifications.Notifier): - def __init__(self, *args, **kwargs): - Notifications.Notifier.__init__(self, *args, **kwargs) - logging.info("args: " + str(args)) - logging.info("kwargs: " + str(kwargs)) - self._deviceListLock = threading.RLock() - with self._deviceListLock: - self.devices = [] - - def __len__(self): - return len(self.devices) - - def __repr__(self): - return "Sniffer Device List: " + str(self.asList()) - - def clear(self): - logging.info("Clearing") - with self._deviceListLock: - self.devices = [] - self.notify("DEVICES_CLEARED") - - def appendOrUpdate(self, newDevice): - with self._deviceListLock: - existingDevice = self.find(newDevice) - - # Add device to the list of devices being displayed, but only if CRC is OK - if existingDevice == None: - self.append(newDevice) - else: - updated = False - if (newDevice.name != '""') and (existingDevice.name == '""'): - existingDevice.name = newDevice.name - updated = True - - if ( - newDevice.RSSI != 0 - and (existingDevice.RSSI < (newDevice.RSSI - 5)) - or (existingDevice.RSSI > (newDevice.RSSI + 2)) - ): - existingDevice.RSSI = newDevice.RSSI - updated = True - - if updated: - self.notify("DEVICE_UPDATED", existingDevice) - - def append(self, device): - self.devices.append(device) - self.notify("DEVICE_ADDED", device) - - def find(self, id): - if type(id) == list: - for dev in self.devices: - if dev.address == id: - return dev - elif type(id) == int: - return self.devices[id] - elif type(id) == str: - for dev in self.devices: - if dev.name in [id, '"' + id + '"']: - return dev - elif id.__class__.__name__ == "Device": - return self.find(id.address) - return None - - def remove(self, id): - if type(id) == list: # address - device = self.devices.pop(self.devices.index(self.find(id))) - elif type(id) == int: - device = self.devices.pop(id) - elif type(id) == Device: - device = self.devices.pop(self.devices.index(self.find(id.address))) - self.notify("DEVICE_REMOVED", device) - - def index(self, device): - index = 0 - for dev in self.devices: - if dev.address == device.address: - return index - index += 1 - return None - - def setFollowed(self, device): - if device in self.devices: - for dev in self.devices: - dev.followed = False - device.followed = True - self.notify("DEVICE_FOLLOWED", device) - - def asList(self): - return self.devices[:] - - -class Device: - def __init__(self, address, name, RSSI): - self.address = address - self.name = name - self.RSSI = RSSI - self.followed = False - - def __repr__(self): - return 'Bluetooth LE device "' + self.name + '" (' + str(self.address) + ")" - - -def listToString(list): - str = "" - for i in list: - str += chr(i) - return str diff --git a/modules/wireshark/extcap/SnifferAPI/Exceptions.py b/modules/wireshark/extcap/SnifferAPI/Exceptions.py deleted file mode 100644 index 86f356a..0000000 --- a/modules/wireshark/extcap/SnifferAPI/Exceptions.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -class SnifferTimeout(Exception): - pass - - -class UARTPacketError(Exception): - pass - - -class LockedException(Exception): - def __init__(self, message): - self.message = message - - -class InvalidPacketException(Exception): - pass - - -class InvalidAdvChannel(Exception): - pass - - -# Internal Use -class SnifferWatchDogTimeout(SnifferTimeout): - pass - - -# Internal Use -class ExitCodeException(Exception): - pass diff --git a/modules/wireshark/extcap/SnifferAPI/Filelock.py b/modules/wireshark/extcap/SnifferAPI/Filelock.py deleted file mode 100644 index 7bf21b5..0000000 --- a/modules/wireshark/extcap/SnifferAPI/Filelock.py +++ /dev/null @@ -1,67 +0,0 @@ -import os -import logging -from sys import platform - -if platform == "linux": - import psutil - -from . import Exceptions - -# Lock file management. -# ref: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch05s09.html -# -# Stored in /var/lock: -# The naming convention which must be used is "LCK.." followed by the base name of the device. -# For example, to lock /dev/ttyS0 the file "LCK..ttyS0" would be created. -# HDB UUCP lock file format: -# process identifier (PID) as a ten byte ASCII decimal number, with a trailing newline - - -def lockpid(lockfile): - if os.path.isfile(lockfile): - with open(lockfile) as fd: - lockpid = fd.read() - - try: - return int(lockpid) - except: - logging.info("Lockfile is invalid. Overriding it..") - os.remove(lockfile) - return 0 - - return 0 - - -def lock(port): - if platform != "linux": - return - - tty = os.path.basename(port) - lockfile = os.path.join("/run", "user", f"{os.getuid()}", f"{tty}.lock") - - lockedpid = lockpid(lockfile) - if lockedpid: - if lockedpid == os.getpid(): - return - - if psutil.pid_exists(lockedpid): - raise Exceptions.LockedException(f"Device {port} is locked") - else: - logging.info("Lockfile is stale. Overriding it..") - os.remove(lockfile) - - fd = open(lockfile, "w") - with open(lockfile, "w") as fd: - fd.write(f"{os.getpid():10}") - - -def unlock(port): - if platform != "linux": - return - - tty = os.path.basename(port) - lockfile = f"/var/lock/LCK..{tty}" - - lockedpid = lockpid(lockfile) - if lockedpid == os.getpid(): - os.remove(lockfile) diff --git a/modules/wireshark/extcap/SnifferAPI/Logger.py b/modules/wireshark/extcap/SnifferAPI/Logger.py deleted file mode 100644 index 228a0f1..0000000 --- a/modules/wireshark/extcap/SnifferAPI/Logger.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -import time, os, logging, traceback, threading -import logging.handlers as logHandlers - -################################################################# -# This file contains the logger. To log a line, simply write # -# 'logging.[level]("whatever you want to log")' # -# [level] is one of {info, debug, warning, error, critical, # -# exception} # -# See python logging documentation # -# As long as Logger.initLogger has been called beforehand, this # -# will result in the line being appended to the log file # -################################################################# - -appdata = os.getenv("appdata") -if appdata: - DEFAULT_LOG_FILE_DIR = os.path.join( - appdata, "Nordic Semiconductor", "Sniffer", "logs" - ) -else: - DEFAULT_LOG_FILE_DIR = "/tmp/logs" - -DEFAULT_LOG_FILE_NAME = "log.txt" - -logFileName = None -logHandler = None -logHandlerArray = [] -logFlusher = None - -myMaxBytes = 1000000 - - -def setLogFileName(log_file_path): - global logFileName - logFileName = os.path.abspath(log_file_path) - - -# Ensure that the directory we are writing the log file to exists. -# Create our logfile, and write the timestamp in the first line. -def initLogger(): - try: - global logFileName - if logFileName is None: - logFileName = os.path.join(DEFAULT_LOG_FILE_DIR, DEFAULT_LOG_FILE_NAME) - - # First, make sure that the directory exists - if not os.path.isdir(os.path.dirname(logFileName)): - os.makedirs(os.path.dirname(logFileName)) - - # If the file does not exist, create it, and save the timestamp - if not os.path.isfile(logFileName): - with open(logFileName, "w") as f: - f.write(str(time.time()) + str(os.linesep)) - - global logFlusher - global logHandlerArray - - logHandler = MyRotatingFileHandler( - logFileName, mode="a", maxBytes=myMaxBytes, backupCount=3 - ) - logFormatter = logging.Formatter( - "%(asctime)s %(levelname)s: %(message)s", datefmt="%d-%b-%Y %H:%M:%S (%z)" - ) - logHandler.setFormatter(logFormatter) - logger = logging.getLogger() - logger.addHandler(logHandler) - logger.setLevel(logging.INFO) - logFlusher = LogFlusher(logHandler) - logHandlerArray.append(logHandler) - except: - print("LOGGING FAILED") - print(traceback.format_exc()) - raise - - -def shutdownLogger(): - if logFlusher is not None: - logFlusher.stop() - logging.shutdown() - - -# Clear the log (typically after it has been sent on email) -def clearLog(): - try: - logHandler.doRollover() - except: - print("LOGGING FAILED") - raise - - -# Returns the timestamp residing on the first line of the logfile. Used for checking the time of creation -def getTimestamp(): - try: - with open(logFileName, "r") as f: - f.seek(0) - return f.readline() - except: - print("LOGGING FAILED") - - -def addTimestamp(): - try: - with open(logFileName, "a") as f: - f.write(str(time.time()) + os.linesep) - except: - print("LOGGING FAILED") - - -# Returns the entire content of the logfile. Used when sending emails -def readAll(): - try: - text = "" - with open(logFileName, "r") as f: - text = f.read() - return text - except: - print("LOGGING FAILED") - - -def addLogHandler(logHandler): - global logHandlerArray - logger = logging.getLogger() - logger.addHandler(logHandler) - logger.setLevel(logging.INFO) - logHandlerArray.append(logHandler) - - -def removeLogHandler(logHandler): - global logHandlerArray - logger = logging.getLogger() - logger.removeHandler(logHandler) - logHandlerArray.remove(logHandler) - - -class MyRotatingFileHandler(logHandlers.RotatingFileHandler): - def doRollover(self): - try: - logHandlers.RotatingFileHandler.doRollover(self) - addTimestamp() - self.maxBytes = myMaxBytes - except: - # There have been permissions issues with the log files. - self.maxBytes += int(myMaxBytes / 2) - - -class LogFlusher(threading.Thread): - def __init__(self, logHandler): - threading.Thread.__init__(self) - - self.daemon = True - self.handler = logHandler - self.exit = threading.Event() - - self.start() - - def run(self): - while True: - if self.exit.wait(10): - try: - self.doFlush() - except AttributeError as e: - print(e) - break - self.doFlush() - - def doFlush(self): - self.handler.flush() - os.fsync(self.handler.stream.fileno()) - - def stop(self): - self.exit.set() - - -if __name__ == "__main__": - initLogger() - for i in range(50): - logging.info("test log no. " + str(i)) - print("test log no. ", i) diff --git a/modules/wireshark/extcap/SnifferAPI/Notifications.py b/modules/wireshark/extcap/SnifferAPI/Notifications.py deleted file mode 100644 index b7cba37..0000000 --- a/modules/wireshark/extcap/SnifferAPI/Notifications.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -import threading, logging - - -class Notification: - def __init__(self, key, msg=None): - if type(key) is not str: - raise TypeError("Invalid notification key: " + str(key)) - self.key = key - self.msg = msg - - def __repr__(self): - return "Notification (key: %s, msg: %s)" % (str(self.key), str(self.msg)) - - -class Notifier: - def __init__(self, callbacks=[], **kwargs): - self.callbacks = {} - self.callbackLock = threading.RLock() - - for callback in callbacks: - self.subscribe(*callback) - - def clearCallbacks(self): - with self.callbackLock: - self.callbacks.clear() - - def subscribe(self, key, callback): - with self.callbackLock: - if callback not in self.getCallbacks(key): - self.getCallbacks(key).append(callback) - - def unSubscribe(self, key, callback): - with self.callbackLock: - if callback in self.getCallbacks(key): - self.getCallbacks(key).remove(callback) - - def getCallbacks(self, key): - with self.callbackLock: - if key not in self.callbacks: - self.callbacks[key] = [] - return self.callbacks[key] - - def notify(self, key=None, msg=None, notification=None): - with self.callbackLock: - if notification == None: - notification = Notification(key, msg) - - for callback in self.getCallbacks(notification.key): - callback(notification) - - for callback in self.getCallbacks("*"): - callback(notification) - - def passOnNotification(self, notification): - self.notify(notification=notification) diff --git a/modules/wireshark/extcap/SnifferAPI/Packet.py b/modules/wireshark/extcap/SnifferAPI/Packet.py deleted file mode 100644 index bc4abd9..0000000 --- a/modules/wireshark/extcap/SnifferAPI/Packet.py +++ /dev/null @@ -1,651 +0,0 @@ -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -from . import UART, Exceptions, Notifications -import time, logging, os, sys, serial -from .Types import * - -ADV_ACCESS_ADDRESS = [0xD6, 0xBE, 0x89, 0x8E] - -SYNCWORD_POS = 0 -PAYLOAD_LEN_POS_V1 = 1 -PAYLOAD_LEN_POS = 0 -PROTOVER_POS = PAYLOAD_LEN_POS + 2 -PACKETCOUNTER_POS = PROTOVER_POS + 1 -ID_POS = PACKETCOUNTER_POS + 2 - -BLE_HEADER_LEN_POS = ID_POS + 1 -FLAGS_POS = BLE_HEADER_LEN_POS + 1 -CHANNEL_POS = FLAGS_POS + 1 -RSSI_POS = CHANNEL_POS + 1 -EVENTCOUNTER_POS = RSSI_POS + 1 -TIMESTAMP_POS = EVENTCOUNTER_POS + 2 -BLEPACKET_POS = TIMESTAMP_POS + 4 -TXADD_POS = BLEPACKET_POS + 4 -TXADD_MSK = 0x40 -PAYLOAD_POS = BLE_HEADER_LEN_POS - -HEADER_LENGTH = 6 -BLE_HEADER_LENGTH = 10 - -VALID_ADV_CHANS = [37, 38, 39] - -PACKET_COUNTER_CAP = 2**16 - - -class PacketReader(Notifications.Notifier): - def __init__(self, portnum=None, callbacks=[], baudrate=None): - Notifications.Notifier.__init__(self, callbacks) - self.portnum = portnum - try: - self.uart = UART.Uart(portnum, baudrate) - except serial.SerialException as e: - logging.exception("Error opening UART %s" % str(e)) - self.uart = UART.Uart() - self.packetCounter = 0 - self.lastReceivedPacketCounter = 0 - self.lastReceivedPacket = None - self.lastReceivedTimestampPacket = None - self.supportedProtocolVersion = PROTOVER_V3 - - def setup(self): - pass - - def doExit(self): - # This method will always join the Uart worker thread - self.uart.close() - # Clear method references to avoid uncollectable cyclic references - self.clearCallbacks() - - # This function takes a byte list, encode it in SLIP protocol and return the encoded byte list - def encodeToSLIP(self, byteList): - tempSLIPBuffer = [] - tempSLIPBuffer.append(SLIP_START) - for i in byteList: - if i == SLIP_START: - tempSLIPBuffer.append(SLIP_ESC) - tempSLIPBuffer.append(SLIP_ESC_START) - elif i == SLIP_END: - tempSLIPBuffer.append(SLIP_ESC) - tempSLIPBuffer.append(SLIP_ESC_END) - elif i == SLIP_ESC: - tempSLIPBuffer.append(SLIP_ESC) - tempSLIPBuffer.append(SLIP_ESC_ESC) - else: - tempSLIPBuffer.append(i) - tempSLIPBuffer.append(SLIP_END) - return tempSLIPBuffer - - # This function uses getSerialByte() function to get SLIP encoded bytes from the serial port and return a decoded byte list - # Based on https://github.com/mehdix/pyslip/ - def decodeFromSLIP(self, timeout=None, complete_timeout=None): - dataBuffer = [] - startOfPacket = False - endOfPacket = False - - if complete_timeout is not None: - time_start = time.time() - - while not startOfPacket and ( - complete_timeout is None or (time.time() - time_start < complete_timeout) - ): - res = self.getSerialByte(timeout) - startOfPacket = res == SLIP_START - - while not endOfPacket and ( - complete_timeout is None or (time.time() - time_start < complete_timeout) - ): - serialByte = self.getSerialByte(timeout) - if serialByte == SLIP_END: - endOfPacket = True - elif serialByte == SLIP_ESC: - serialByte = self.getSerialByte(timeout) - if serialByte == SLIP_ESC_START: - dataBuffer.append(SLIP_START) - elif serialByte == SLIP_ESC_END: - dataBuffer.append(SLIP_END) - elif serialByte == SLIP_ESC_ESC: - dataBuffer.append(SLIP_ESC) - else: - dataBuffer.append(SLIP_END) - else: - dataBuffer.append(serialByte) - if not endOfPacket: - raise Exceptions.UARTPacketError( - "Exceeded max timeout of %f seconds." % complete_timeout - ) - return dataBuffer - - # This function read byte chuncks from the serial port and return one byte at a time - # Based on https://github.com/mehdix/pyslip/ - def getSerialByte(self, timeout=None): - serialByte = self.uart.readByte(timeout) - if serialByte is None: - raise Exceptions.SnifferTimeout("Packet read timed out.") - return serialByte - - def handlePacketHistory(self, packet): - # Reads and validates packet counter - if ( - self.lastReceivedPacket is not None - and packet.packetCounter - != (self.lastReceivedPacket.packetCounter + 1) % PACKET_COUNTER_CAP - and self.lastReceivedPacket.packetCounter != 0 - ): - - logging.info( - "gap in packets, between " - + str(self.lastReceivedPacket.packetCounter) - + " and " - + str(packet.packetCounter) - + " packet before: " - + str(self.lastReceivedPacket.packetList) - + " packet after: " - + str(packet.packetList) - ) - - self.lastReceivedPacket = packet - if packet.id in [EVENT_PACKET_DATA_PDU, EVENT_PACKET_ADV_PDU]: - self.lastReceivedTimestampPacket = packet - - def getPacketTime(self, packet): - ble_payload_length = self.lastReceivedPacket.payloadLength - BLE_HEADER_LENGTH - - if packet.phy == PHY_1M: - return 8 * (1 + ble_payload_length) - elif packet.phy == PHY_2M: - return 4 * (2 + ble_payload_length) - elif packet.phy == PHY_CODED: - # blePacket is not assigned if not packet is "OK" (CRC error) - ci = packet.packetList[BLEPACKET_POS + 4] - fec2_block_len = ble_payload_length - 4 - 1 - fec1_block_us = 80 + 256 + 16 + 24 - if ci == PHY_CODED_CI_S8: - return fec1_block_us + 64 * fec2_block_len + 24 - elif ci == PHY_CODED_CI_S2: - return fec1_block_us + 16 * fec2_block_len + 6 - # Unknown PHY or Coding Indicator - return 0 - - def convertPacketListProtoVer2(self, packet): - # Convert to version 2 - packet.packetList[PROTOVER_POS] = 2 - - # Convert to common packet ID - if packet.packetList[ID_POS] == EVENT_PACKET_ADV_PDU: - packet.packetList[ID_POS] = EVENT_PACKET_DATA_PDU - - if packet.packetList[ID_POS] != EVENT_PACKET_DATA_PDU: - # These types do not have a timestamp - return - - # Convert time-stamp to End to Start delta - time_delta = 0 - if ( - self.lastReceivedTimestampPacket is not None - and self.lastReceivedTimestampPacket.valid - ): - time_delta = packet.timestamp - ( - self.lastReceivedTimestampPacket.timestamp - + self.getPacketTime(self.lastReceivedTimestampPacket) - ) - - time_delta = toLittleEndian(time_delta, 4) - packet.packetList[TIMESTAMP_POS] = time_delta[0] - packet.packetList[TIMESTAMP_POS + 1] = time_delta[1] - packet.packetList[TIMESTAMP_POS + 2] = time_delta[2] - packet.packetList[TIMESTAMP_POS + 3] = time_delta[3] - - def handlePacketCompatibility(self, packet): - if ( - self.supportedProtocolVersion == PROTOVER_V2 - and packet.packetList[PROTOVER_POS] > PROTOVER_V2 - ): - self.convertPacketListProtoVer2(packet) - - def setSupportedProtocolVersion(self, supportedProtocolVersion): - if supportedProtocolVersion != PROTOVER_V3: - logging.info( - "Using packet compatibility, converting packets to protocol version %d", - supportedProtocolVersion, - ) - self.supportedProtocolVersion = supportedProtocolVersion - - def getPacket(self, timeout=None): - packetList = [] - try: - packetList = self.decodeFromSLIP(timeout) - except Exceptions.UARTPacketError: # FIXME: This is never thrown... - logging.exception("") - return None - else: - packet = Packet(packetList) - if packet.valid: - self.handlePacketCompatibility(packet) - self.handlePacketHistory(packet) - return packet - - def sendPacket(self, id, payload): - packetList = ( - [HEADER_LENGTH] - + [len(payload)] - + [PROTOVER_V1] - + toLittleEndian(self.packetCounter, 2) - + [id] - + payload - ) - packetList = self.encodeToSLIP(packetList) - self.packetCounter += 1 - self.uart.writeList(packetList) - - def sendScan(self, findScanRsp=False, findAux=False, scanCoded=False): - flags0 = findScanRsp | (findAux << 1) | (scanCoded << 2) - self.sendPacket(REQ_SCAN_CONT, [flags0]) - logging.info("Scan flags: %s" % bin(flags0)) - - def sendFollow( - self, - addr, - followOnlyAdvertisements=False, - followOnlyLegacy=False, - followCoded=False, - ): - flags0 = followOnlyAdvertisements | (followOnlyLegacy << 1) | (followCoded << 2) - logging.info("Follow flags: %s" % bin(flags0)) - self.sendPacket(REQ_FOLLOW, addr + [flags0]) - - def sendPingReq(self): - self.sendPacket(PING_REQ, []) - - def getBytes(self, value, size): - if len(value) < size: - value = [0] * (size - len(value)) + value - else: - value = value[:size] - - return value - - def sendTK(self, TK): - TK = self.getBytes(TK, 16) - self.sendPacket(SET_TEMPORARY_KEY, TK) - logging.info("Sent TK to sniffer: " + str(TK)) - - def sendPrivateKey(self, pk): - pk = self.getBytes(pk, 32) - self.sendPacket(SET_PRIVATE_KEY, pk) - logging.info("Sent private key to sniffer: " + str(pk)) - - def sendLegacyLTK(self, ltk): - ltk = self.getBytes(ltk, 16) - self.sendPacket(SET_LEGACY_LONG_TERM_KEY, ltk) - logging.info("Sent Legacy LTK to sniffer: " + str(ltk)) - - def sendSCLTK(self, ltk): - ltk = self.getBytes(ltk, 16) - self.sendPacket(SET_SC_LONG_TERM_KEY, ltk) - logging.info("Sent SC LTK to sniffer: " + str(ltk)) - - def sendIRK(self, irk): - irk = self.getBytes(irk, 16) - self.sendPacket(SET_IDENTITY_RESOLVING_KEY, irk) - logging.info("Sent IRK to sniffer: " + str(irk)) - - def sendSwitchBaudRate(self, newBaudRate): - self.sendPacket(SWITCH_BAUD_RATE_REQ, toLittleEndian(newBaudRate, 4)) - - def switchBaudRate(self, newBaudRate): - self.uart.switchBaudRate(newBaudRate) - - def sendHopSequence(self, hopSequence): - for chan in hopSequence: - if chan not in VALID_ADV_CHANS: - raise Exceptions.InvalidAdvChannel( - "%s is not an adv channel" % str(chan) - ) - payload = [len(hopSequence)] + hopSequence + [37] * (3 - len(hopSequence)) - self.sendPacket(SET_ADV_CHANNEL_HOP_SEQ, payload) - self.notify("NEW_ADV_HOP_SEQ", {"hopSequence": hopSequence}) - - def sendVersionReq(self): - self.sendPacket(REQ_VERSION, []) - - def sendTimestampReq(self): - self.sendPacket(REQ_TIMESTAMP, []) - - def sendGoIdle(self): - self.sendPacket(GO_IDLE, []) - - -class Packet: - def __init__(self, packetList): - try: - if not packetList: - raise Exceptions.InvalidPacketException( - "packet list not valid: %s" % str(packetList) - ) - - self.protover = packetList[PROTOVER_POS] - - if self.protover > PROTOVER_V3: - logging.exception( - "Unsupported protocol version %s" % str(self.protover) - ) - raise RuntimeError( - "Unsupported protocol version %s" % str(self.protover) - ) - - self.packetCounter = parseLittleEndian( - packetList[PACKETCOUNTER_POS : PACKETCOUNTER_POS + 2] - ) - self.id = packetList[ID_POS] - - if int(self.protover) == PROTOVER_V1: - self.payloadLength = packetList[PAYLOAD_LEN_POS_V1] - else: - self.payloadLength = parseLittleEndian( - packetList[PAYLOAD_LEN_POS : PAYLOAD_LEN_POS + 2] - ) - - self.packetList = packetList - self.readPayload(packetList) - - except Exceptions.InvalidPacketException as e: - logging.error("Invalid packet: %s" % str(e)) - self.OK = False - self.valid = False - except Exception as e: - logging.exception("packet creation error %s" % str(e)) - logging.info("packetList: " + str(packetList)) - self.OK = False - self.valid = False - - def __repr__(self): - return "UART packet, type: " + str(self.id) + ", PC: " + str(self.packetCounter) - - def readPayload(self, packetList): - self.blePacket = None - self.OK = False - - if not self.validatePacketList(packetList): - raise Exceptions.InvalidPacketException( - "packet list not valid: %s" % str(packetList) - ) - else: - self.valid = True - - self.payload = packetList[PAYLOAD_POS : PAYLOAD_POS + self.payloadLength] - - if self.id == EVENT_PACKET_ADV_PDU or self.id == EVENT_PACKET_DATA_PDU: - try: - self.bleHeaderLength = packetList[BLE_HEADER_LEN_POS] - if self.bleHeaderLength == BLE_HEADER_LENGTH: - self.flags = packetList[FLAGS_POS] - self.readFlags() - self.channel = packetList[CHANNEL_POS] - self.rawRSSI = packetList[RSSI_POS] - self.RSSI = -self.rawRSSI - self.eventCounter = parseLittleEndian( - packetList[EVENTCOUNTER_POS : EVENTCOUNTER_POS + 2] - ) - - self.timestamp = parseLittleEndian( - packetList[TIMESTAMP_POS : TIMESTAMP_POS + 4] - ) - - # The hardware adds a padding byte which isn't sent on air. - # We remove it, and update the payload length in the packet list. - if self.phy == PHY_CODED: - self.packetList.pop(BLEPACKET_POS + 6 + 1) - else: - self.packetList.pop(BLEPACKET_POS + 6) - self.payloadLength -= 1 - if self.protover >= PROTOVER_V2: - # Write updated payload length back to the packet list. - payloadLength = toLittleEndian(self.payloadLength, 2) - packetList[PAYLOAD_LEN_POS] = payloadLength[0] - packetList[PAYLOAD_LEN_POS + 1] = payloadLength[1] - else: # PROTOVER_V1 - packetList[PAYLOAD_LEN_POS_V1] = self.payloadLength - else: - logging.info("Invalid BLE Header Length " + str(packetList)) - self.valid = False - - if self.OK: - try: - if self.protover >= PROTOVER_V3: - packet_type = ( - PACKET_TYPE_ADVERTISING - if self.id == EVENT_PACKET_ADV_PDU - else PACKET_TYPE_DATA - ) - else: - packet_type = ( - PACKET_TYPE_ADVERTISING - if packetList[BLEPACKET_POS : BLEPACKET_POS + 4] - == ADV_ACCESS_ADDRESS - else PACKET_TYPE_DATA - ) - - self.blePacket = BlePacket( - packet_type, packetList[BLEPACKET_POS:], self.phy - ) - except Exception as e: - logging.exception("blePacket error %s" % str(e)) - except Exception as e: - # malformed packet - logging.exception("packet error %s" % str(e)) - self.OK = False - elif self.id == PING_RESP: - if self.protover < PROTOVER_V3: - self.version = parseLittleEndian( - packetList[PAYLOAD_POS : PAYLOAD_POS + 2] - ) - elif self.id == RESP_VERSION: - self.version = "".join([chr(i) for i in packetList[PAYLOAD_POS:]]) - elif self.id == RESP_TIMESTAMP: - self.timestamp = parseLittleEndian( - packetList[PAYLOAD_POS : PAYLOAD_POS + 4] - ) - elif self.id == SWITCH_BAUD_RATE_RESP or self.id == SWITCH_BAUD_RATE_REQ: - self.baudRate = parseLittleEndian(packetList[PAYLOAD_POS : PAYLOAD_POS + 4]) - else: - logging.info("Unknown packet ID") - - def readFlags(self): - self.crcOK = not not (self.flags & 1) - self.direction = not not (self.flags & 2) - self.encrypted = not not (self.flags & 4) - self.micOK = not not (self.flags & 8) - self.phy = (self.flags >> 4) & 7 - self.OK = self.crcOK and (self.micOK or not self.encrypted) - - def getList(self): - return self.packetList - - def validatePacketList(self, packetList): - try: - if (self.payloadLength + HEADER_LENGTH) == len(packetList): - return True - else: - return False - except: - logging.exception("Invalid packet: %s" % str(packetList)) - return False - - -class BlePacket: - def __init__(self, type, packetList, phy): - self.type = type - - offset = 0 - offset = self.extractAccessAddress(packetList, offset) - offset = self.extractFormat(packetList, phy, offset) - - if self.type == PACKET_TYPE_ADVERTISING: - offset = self.extractAdvHeader(packetList, offset) - else: - offset = self.extractConnHeader(packetList, offset) - - offset = self.extractLength(packetList, offset) - self.payload = packetList[offset:] - - if self.type == PACKET_TYPE_ADVERTISING: - offset = self.extractAddresses(packetList, offset) - self.extractName(packetList, offset) - - def __repr__(self): - return "BLE packet, AAddr: " + str(self.accessAddress) - - def extractAccessAddress(self, packetList, offset): - self.accessAddress = packetList[offset : offset + 4] - return offset + 4 - - def extractFormat(self, packetList, phy, offset): - self.coded = phy == PHY_CODED - if self.coded: - self.codingIndicator = packetList[offset] & 3 - return offset + 1 - - return offset - - def extractAdvHeader(self, packetList, offset): - self.advType = packetList[offset] & 15 - self.txAddrType = (packetList[offset] >> 6) & 1 - if self.advType in [1, 3, 5]: - self.rxAddrType = (packetList[offset] << 7) & 1 - elif self.advType == 7: - flags = packetList[offset + 2] - if flags & 0x02: - self.rxAddrType = (packetList[offset] << 7) & 1 - return offset + 1 - - def extractConnHeader(self, packetList, offset): - self.llid = packetList[offset] & 3 - self.sn = (packetList[offset] >> 2) & 1 - self.nesn = (packetList[offset] >> 3) & 1 - self.md = (packetList[offset] >> 4) & 1 - return offset + 1 - - def extractAddresses(self, packetList, offset): - addr = None - scanAddr = None - - if self.advType in [0, 1, 2, 4, 6]: - addr = packetList[offset : offset + 6] - addr.reverse() - addr += [self.txAddrType] - offset += 6 - - if self.advType in [3, 5]: - scanAddr = packetList[offset : offset + 6] - scanAddr.reverse() - scanAddr += [self.txAddrType] - offset += 6 - addr = packetList[offset : offset + 6] - addr.reverse() - addr += [self.rxAddrType] - offset += 6 - - if self.advType == 1: - scanAddr = packetList[offset : offset + 6] - scanAddr.reverse() - scanAddr += [self.rxAddrType] - offset += 6 - - if self.advType == 7: - ext_header_len = packetList[offset] & 0x3F - offset += 1 - - ext_header_offset = offset - flags = packetList[offset] - ext_header_offset += 1 - - if flags & 0x01: - addr = packetList[ext_header_offset : ext_header_offset + 6] - addr.reverse() - addr += [self.txAddrType] - ext_header_offset += 6 - - if flags & 0x02: - scanAddr = packetList[ext_header_offset : ext_header_offset + 6] - scanAddr.reverse() - scanAddr += [self.rxAddrType] - ext_header_offset += 6 - - offset += ext_header_len - - self.advAddress = addr - self.scanAddress = scanAddr - return offset - - def extractName(self, packetList, offset): - name = "" - if self.advType in [0, 2, 4, 6, 7]: - i = offset - while i < len(packetList): - length = packetList[i] - if (i + length + 1) > len(packetList) or length == 0: - break - type = packetList[i + 1] - if type == 8 or type == 9: - nameList = packetList[i + 2 : i + length + 1] - name = "" - for j in nameList: - name += chr(j) - i += length + 1 - name = '"' + name + '"' - elif self.advType == 1: - name = "[ADV_DIRECT_IND]" - - self.name = name - - def extractLength(self, packetList, offset): - self.length = packetList[offset] - return offset + 1 - - -def parseLittleEndian(list): - total = 0 - for i in range(len(list)): - total += list[i] << (8 * i) - return total - - -def toLittleEndian(value, size): - list = [0] * size - for i in range(size): - list[i] = (value >> (i * 8)) % 256 - return list diff --git a/modules/wireshark/extcap/SnifferAPI/Pcap.py b/modules/wireshark/extcap/SnifferAPI/Pcap.py deleted file mode 100644 index 8b0445a..0000000 --- a/modules/wireshark/extcap/SnifferAPI/Pcap.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -import struct - - -# See: -# - https://github.com/pcapng/pcapng -# - https://www.tcpdump.org/linktypes/LINKTYPE_NORDIC_BLE.html -PACKET_HEADER = struct.Struct("= PROTOVER_V3: - if self._last_time is None: - # Timestamp from Host - packet.time = time.time() - else: - # Timestamp using reference and packet timestamp diff - if packet.timestamp < self._last_timestamp: - time_diff = (1 << 32) - (self._last_timestamp - packet.timestamp) - else: - time_diff = packet.timestamp - self._last_timestamp - - packet.time = self._last_time + (time_diff / 1_000_000) - - self._last_time = packet.time - self._last_timestamp = packet.timestamp - else: - # Timestamp from Host - packet.time = time.time() - - self._appendPacket(packet) - - self.notify("NEW_BLE_PACKET", {"packet": packet}) - self._captureHandler.writePacket(packet) - - self._nProcessedPackets += 1 - if packet.OK: - try: - if packet.blePacket.type == PACKET_TYPE_ADVERTISING: - - if self.state == STATE_FOLLOWING and packet.blePacket.advType == 5: - self._connectionAccessAddress = packet.blePacket.accessAddress - - if self.state == STATE_FOLLOWING and packet.blePacket.advType == 4: - newDevice = Devices.Device( - address=packet.blePacket.advAddress, - name=packet.blePacket.name, - RSSI=packet.RSSI, - ) - self._devices.appendOrUpdate(newDevice) - - if self.state == STATE_SCANNING: - if ( - packet.blePacket.advType in [0, 1, 2, 4, 6, 7] - and packet.blePacket.advAddress != None - and packet.crcOK - and not packet.direction - ): - newDevice = Devices.Device( - address=packet.blePacket.advAddress, - name=packet.blePacket.name, - RSSI=packet.RSSI, - ) - self._devices.appendOrUpdate(newDevice) - - except Exception as e: - logging.exception("packet processing error %s" % str(e)) - self.notify("PACKET_PROCESSING_ERROR", {"errorString": str(e)}) - - def _continuouslyPipe(self): - while not self._exit: - try: - packet = self._packetReader.getPacket(timeout=12) - if packet == None or not packet.valid: - raise Exceptions.InvalidPacketException("") - except Exceptions.SnifferTimeout as e: - logging.info(str(e)) - packet = None - except (SerialException, ValueError): - logging.exception("UART read error") - logging.error("Lost contact with sniffer hardware.") - self._doExit() - except Exceptions.InvalidPacketException: - pass - else: - if ( - packet.id == EVENT_PACKET_DATA_PDU - or packet.id == EVENT_PACKET_ADV_PDU - ): - self._processBLEPacket(packet) - elif packet.id == EVENT_FOLLOW: - # This packet has no value for the user. - pass - elif packet.id == EVENT_CONNECT: - self._connectEventPacketCounterValue = packet.packetCounter - self._inConnection = True - # copy it because packets are eventually deleted - self._currentConnectRequest = copy.copy( - self._findPacketByPacketCounter( - self._connectEventPacketCounterValue - 1 - ) - ) - elif packet.id == EVENT_DISCONNECT: - if self._inConnection: - self._packetsInLastConnection = ( - packet.packetCounter - self._connectEventPacketCounterValue - ) - self._inConnection = False - elif packet.id == SWITCH_BAUD_RATE_RESP and self._switchingBaudRate: - self._switchingBaudRate = False - if packet.baudRate == self._proposedBaudRate: - self._packetReader.switchBaudRate(self._proposedBaudRate) - else: - self._switchBaudRate(packet.baudRate) - elif packet.id == PING_RESP: - if hasattr(packet, "version"): - versions = { - 1116: "3.1.0", - 1115: "3.0.0", - 1114: "2.0.0", - 1113: "2.0.0-beta-3", - 1112: "2.0.0-beta-1", - } - self._fwversion = versions.get( - packet.version, "SVN rev: %d" % packet.version - ) - logging.info("Firmware version %s" % self._fwversion) - elif packet.id == RESP_VERSION: - self._fwversion = packet.version - logging.info("Firmware version %s" % self._fwversion) - elif packet.id == RESP_TIMESTAMP: - # Use current time as timestamp reference - self._last_time = time.time() - self._last_timestamp = packet.timestamp - - lt = time.localtime(self._last_time) - usecs = int((self._last_time - int(self._last_time)) * 1_000_000) - logging.info( - f"Firmware timestamp {self._last_timestamp} reference: " - f'{time.strftime("%b %d %Y %X", lt)}.{usecs} {time.strftime("%Z", lt)}' - ) - else: - logging.info("Unknown packet ID") - - def _findPacketByPacketCounter(self, packetCounterValue): - with self._packetListLock: - for i in range(-1, -1 - len(self._packets), -1): - # iterate backwards through packets - if self._packets[i].packetCounter == packetCounterValue: - return self._packets[i] - return None - - def _startScanning(self, findScanRsp=False, findAux=False, scanCoded=False): - logging.info("starting scan") - - if self.state == STATE_FOLLOWING: - logging.info("Stopped sniffing device") - - self._setState(STATE_SCANNING) - self._packetReader.sendScan(findScanRsp, findAux, scanCoded) - self._packetReader.sendTK([0]) - - def _doExit(self): - self._exit = True - self.notify("APP_EXIT") - self._packetReader.doExit() - # Clear method references to avoid uncollectable cyclic references - self.clearCallbacks() - self._devices.clearCallbacks() - - def _startFollowing( - self, - device, - followOnlyAdvertisements=False, - followOnlyLegacy=False, - followCoded=False, - ): - self._devices.setFollowed(device) - logging.info( - "Sniffing device " - + str(self._devices.index(device)) - + ' - "' - + device.name - + '"' - ) - self._packetReader.sendFollow( - device.address, followOnlyAdvertisements, followOnlyLegacy, followCoded - ) - self._setState(STATE_FOLLOWING) - - def _clearDevices(self): - self._devices.clear() - - def _appendPacket(self, packet): - with self._packetListLock: - if len(self._packets) > 100000: - self._packets = self._packets[20000:] - self._packets.append(packet) - - def _getPackets(self, number=-1): - with self._packetListLock: - returnList = self._packets[0:number] - self._packets = self._packets[number:] - return returnList - - def _clearPackets(self): - with self._packetListLock: - del self._packets[:] diff --git a/modules/wireshark/extcap/SnifferAPI/Types.py b/modules/wireshark/extcap/SnifferAPI/Types.py deleted file mode 100644 index eac7609..0000000 --- a/modules/wireshark/extcap/SnifferAPI/Types.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -SLIP_START = 0xAB -SLIP_END = 0xBC -SLIP_ESC = 0xCD -SLIP_ESC_START = SLIP_START + 1 -SLIP_ESC_END = SLIP_END + 1 -SLIP_ESC_ESC = SLIP_ESC + 1 - -PROTOVER_V3 = 3 -PROTOVER_V2 = 2 -PROTOVER_V1 = 1 - -# UART protocol packet codes (see sniffer_uart_protocol.pdf) -REQ_FOLLOW = 0x00 -EVENT_FOLLOW = 0x01 -EVENT_PACKET_ADV_PDU = 0x02 -EVENT_CONNECT = 0x05 -EVENT_PACKET_DATA_PDU = 0x06 -REQ_SCAN_CONT = 0x07 -EVENT_DISCONNECT = 0x09 -SET_TEMPORARY_KEY = 0x0C -PING_REQ = 0x0D -PING_RESP = 0x0E -SWITCH_BAUD_RATE_REQ = 0x13 -SWITCH_BAUD_RATE_RESP = 0x14 -SET_ADV_CHANNEL_HOP_SEQ = 0x17 -SET_PRIVATE_KEY = 0x18 -SET_LEGACY_LONG_TERM_KEY = 0x19 -SET_SC_LONG_TERM_KEY = 0x1A -REQ_VERSION = 0x1B -RESP_VERSION = 0x1C -REQ_TIMESTAMP = 0x1D -RESP_TIMESTAMP = 0x1E -SET_IDENTITY_RESOLVING_KEY = 0x1F -GO_IDLE = 0xFE - -PACKET_TYPE_UNKNOWN = 0x00 -PACKET_TYPE_ADVERTISING = 0x01 -PACKET_TYPE_DATA = 0x02 - -ADV_TYPE_ADV_IND = 0x0 -ADV_TYPE_ADV_DIRECT_IND = 0x1 -ADV_TYPE_ADV_NONCONN_IND = 0x2 -ADV_TYPE_ADV_SCAN_IND = 0x6 -ADV_TYPE_SCAN_REQ = 0x3 -ADV_TYPE_SCAN_RSP = 0x4 -ADV_TYPE_CONNECT_REQ = 0x5 -ADV_TYPE_ADV_EXT_IND = 0x7 - -PHY_1M = 0 -PHY_2M = 1 -PHY_CODED = 2 - -PHY_CODED_CI_S8 = 0 -PHY_CODED_CI_S2 = 1 diff --git a/modules/wireshark/extcap/SnifferAPI/UART.py b/modules/wireshark/extcap/SnifferAPI/UART.py deleted file mode 100644 index ecd16d2..0000000 --- a/modules/wireshark/extcap/SnifferAPI/UART.py +++ /dev/null @@ -1,238 +0,0 @@ -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import collections -import logging -import serial -from threading import Thread, Event - -import serial.tools.list_ports as list_ports - -from . import Exceptions -from . import Packet -from . import Filelock - -import os - -if os.name == "posix": - import termios - -SNIFFER_OLD_DEFAULT_BAUDRATE = 460800 -# Baudrates that should be tried (add more if required) -SNIFFER_BAUDRATES = [1000000, 460800] - - -def find_sniffer(write_data=False): - open_ports = list_ports.comports() - - sniffers = [] - for port in [x.device for x in open_ports]: - for rate in SNIFFER_BAUDRATES: - reader = None - l_errors = [ - serial.SerialException, - ValueError, - Exceptions.LockedException, - OSError, - ] - if os.name == "posix": - l_errors.append(termios.error) - try: - reader = Packet.PacketReader(portnum=port, baudrate=rate) - try: - if write_data: - reader.sendPingReq() - _ = reader.decodeFromSLIP(0.1, complete_timeout=0.1) - else: - _ = reader.decodeFromSLIP(0.3, complete_timeout=0.3) - - # FIXME: Should add the baud rate here, but that will be a breaking change - sniffers.append(port) - break - except (Exceptions.SnifferTimeout, Exceptions.UARTPacketError): - pass - except tuple(l_errors): - continue - finally: - if reader is not None: - reader.doExit() - return sniffers - - -def find_sniffer_baudrates(port, write_data=False): - for rate in SNIFFER_BAUDRATES: - reader = None - try: - reader = Packet.PacketReader(portnum=port, baudrate=rate) - try: - if write_data: - reader.sendPingReq() - _ = reader.decodeFromSLIP(0.1, complete_timeout=0.1) - else: - _ = reader.decodeFromSLIP(0.3, complete_timeout=0.3) - - # TODO: possibly include additional rates based on protocol version - return {"default": rate, "other": []} - except (Exceptions.SnifferTimeout, Exceptions.UARTPacketError): - pass - finally: - if reader is not None: - reader.doExit() - return None - - -class Uart: - def __init__(self, portnum=None, baudrate=None): - self.ser = None - try: - if baudrate is not None and baudrate not in SNIFFER_BAUDRATES: - raise Exception("Invalid baudrate: " + str(baudrate)) - - logging.info("Opening serial port {}".format(portnum)) - - self.portnum = portnum - if self.portnum: - Filelock.lock(portnum) - - self.ser = serial.Serial( - port=portnum, baudrate=9600, rtscts=True, exclusive=True - ) - self.ser.baudrate = baudrate - - except Exception: - if self.ser: - self.ser.close() - self.ser = None - raise - - self.read_queue = collections.deque() - self.read_queue_has_data = Event() - - self.worker_thread = Thread(target=self._read_worker) - self.reading = True - self.worker_thread.setDaemon(True) - self.worker_thread.start() - - def _read_worker(self): - self.ser.reset_input_buffer() - while self.reading: - try: - # Read any data available, or wait for at least one byte - data_read = self.ser.read(self.ser.in_waiting or 1) - # logging.info('type: {}'.format(data_read.__class__)) - self._read_queue_extend(data_read) - except serial.SerialException as e: - logging.info("Unable to read UART: %s" % e) - self.reading = False - return - - def close(self): - if self.ser: - logging.info("closing UART") - self.reading = False - # Wake any threads waiting on the queue - self.read_queue_has_data.set() - if hasattr(self.ser, "cancel_read"): - self.ser.cancel_read() - self.worker_thread.join() - self.ser.close() - else: - self.ser.close() - self.worker_thread.join() - self.ser = None - - if self.portnum: - Filelock.unlock(self.portnum) - - def __del__(self): - self.close() - - def switchBaudRate(self, newBaudRate): - self.ser.baudrate = newBaudRate - - def readByte(self, timeout=None): - r = self._read_queue_get(timeout) - return r - - def writeList(self, array): - try: - self.ser.write(array) - except serial.SerialTimeoutException: - logging.info("Got write timeout, ignoring error") - - except serial.SerialException as e: - self.ser.close() - raise e - - def _read_queue_extend(self, data): - if len(data) > 0: - self.read_queue.extend(data) - self.read_queue_has_data.set() - - def _read_queue_get(self, timeout=None): - data = None - if self.read_queue_has_data.wait(timeout): - self.read_queue_has_data.clear() - try: - data = self.read_queue.popleft() - except IndexError: - # This will happen when the class is destroyed - return None - if len(self.read_queue) > 0: - self.read_queue_has_data.set() - return data - - -def list_serial_ports(): - # Scan for available ports. - return list_ports.comports() - - -if __name__ == "__main__": - import time - - t_start = time.time() - s = find_sniffer() - tn = time.time() - print(s) - print("find_sniffer took %f seconds" % (tn - t_start)) - for p in s: - t = time.time() - print(find_sniffer_baudrates(p)) - tn = time.time() - print("find_sniffer_baudrate took %f seconds" % (tn - t)) - tn = time.time() - print("total runtime %f" % (tn - t_start)) diff --git a/modules/wireshark/extcap/SnifferAPI/__init__.py b/modules/wireshark/extcap/SnifferAPI/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/modules/wireshark/extcap/SnifferAPI/version.py b/modules/wireshark/extcap/SnifferAPI/version.py deleted file mode 100644 index 5b94c32..0000000 --- a/modules/wireshark/extcap/SnifferAPI/version.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -VERSION_STRING = "4.1.1" diff --git a/modules/wireshark/extcap/nrf_sniffer_ble.py b/modules/wireshark/extcap/nrf_sniffer_ble.py deleted file mode 100644 index 1aa1380..0000000 --- a/modules/wireshark/extcap/nrf_sniffer_ble.py +++ /dev/null @@ -1,991 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) Nordic Semiconductor ASA -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form, except as embedded into a Nordic -# Semiconductor ASA integrated circuit in a product or a software update for -# such product, must reproduce the above copyright notice, this list of -# conditions and the following disclaimer in the documentation and/or other -# materials provided with the distribution. -# -# 3. Neither the name of Nordic Semiconductor ASA nor the names of its -# contributors may be used to endorse or promote products derived from this -# software without specific prior written permission. -# -# 4. This software, with or without modification, must only be used with a -# Nordic Semiconductor ASA integrated circuit. -# -# 5. Any software provided in binary form under this license must not be reverse -# engineered, decompiled, modified and/or disassembled. -# -# THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS -# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -# OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -""" -Wireshark extcap wrapper for the nRF Sniffer for Bluetooth LE by Nordic Semiconductor. -""" - -import os -import sys -import argparse -import re -import time -import struct -import logging - -from SnifferAPI import Logger - -try: - import serial -except ImportError: - Logger.initLogger() - logging.error( - f'pyserial not found, please run: "{sys.executable} -m pip install -r requirements.txt" and retry' - ) - sys.exit( - f'pyserial not found, please run: "{sys.executable} -m pip install -r requirements.txt" and retry' - ) - -from SnifferAPI import Sniffer, UART, Devices, Pcap, Exceptions - -ERROR_USAGE = 0 -ERROR_ARG = 1 -ERROR_INTERFACE = 2 -ERROR_FIFO = 3 -ERROR_INTERNAL = 4 - -CTRL_CMD_INIT = 0 -CTRL_CMD_SET = 1 -CTRL_CMD_ADD = 2 -CTRL_CMD_REMOVE = 3 -CTRL_CMD_ENABLE = 4 -CTRL_CMD_DISABLE = 5 -CTRL_CMD_STATUSBAR = 6 -CTRL_CMD_INFO_MSG = 7 -CTRL_CMD_WARN_MSG = 8 -CTRL_CMD_ERROR_MSG = 9 - -CTRL_ARG_DEVICE = 0 -CTRL_ARG_KEY_TYPE = 1 -CTRL_ARG_KEY_VAL = 2 -CTRL_ARG_ADVHOP = 3 -CTRL_ARG_HELP = 4 -CTRL_ARG_RESTORE = 5 -CTRL_ARG_LOG = 6 -CTRL_ARG_DEVICE_CLEAR = 7 -CTRL_ARG_NONE = 255 - -CTRL_KEY_TYPE_PASSKEY = 0 -CTRL_KEY_TYPE_OOB = 1 -CTRL_KEY_TYPE_LEGACY_LTK = 2 -CTRL_KEY_TYPE_SC_LTK = 3 -CTRL_KEY_TYPE_DH_PRIVATE_KEY = 4 -CTRL_KEY_TYPE_IRK = 5 -CTRL_KEY_TYPE_ADD_ADDR = 6 -CTRL_KEY_TYPE_FOLLOW_ADDR = 7 - -fn_capture = None -fn_ctrl_in = None -fn_ctrl_out = None - -extcap_log_handler = None -extcap_version = None - -# Wireshark nRF Sniffer for Bluetooth LE Toolbar will always cache the last used key and adv hop and send -# this when starting a capture. To ensure that the key and adv hop is always shown correctly -# in the Toolbar, even if the user has changed it but not applied it, we send the last used -# key and adv hop back as a default value. -last_used_key_type = CTRL_KEY_TYPE_PASSKEY -last_used_key_val = "" -last_used_advhop = "37,38,39" - -zero_addr = "[00,00,00,00,00,00,0]" - -# While searching for a selected Device we must not write packets to the pipe until -# the device is found to avoid getting advertising packets from other devices. -write_new_packets = False - -# The RSSI capture filter value given from Wireshark. -rssi_filter = 0 - -# The RSSI filtering is not on when in follow mode. -in_follow_mode = False - -# nRF Sniffer for Bluetooth LE interface option to only capture advertising packets -capture_only_advertising = False -capture_only_legacy_advertising = False -capture_scan_response = True -capture_scan_aux_pointer = True -capture_coded = False - - -def extcap_config(interface): - """List configuration for the given interface""" - print( - "arg {number=0}{call=--only-advertising}{display=Only advertising packets}" - "{tooltip=The sniffer will only capture advertising packets from the selected device}{type=boolflag}{save=true}" - ) - print( - "arg {number=1}{call=--only-legacy-advertising}{display=Only legacy advertising packets}" - "{tooltip=The sniffer will only capture legacy advertising packets from the selected device}{type=boolflag}{save=true}" - ) - print( - "arg {number=2}{call=--scan-follow-rsp}{display=Find scan response data}" - "{tooltip=The sniffer will follow scan requests and scan responses in scan mode}{type=boolflag}{default=true}{save=true}" - ) - print( - "arg {number=3}{call=--scan-follow-aux}{display=Find auxiliary pointer data}" - "{tooltip=The sniffer will follow aux pointers in scan mode}{type=boolflag}{default=true}{save=true}" - ) - print( - "arg {number=3}{call=--coded}{display=Scan and follow devices on LE Coded PHY}" - "{tooltip=Scan for devices and follow advertiser on LE Coded PHY}{type=boolflag}{default=false}{save=true}" - ) - - -def extcap_dlts(interface): - """List DLTs for the given interface""" - print("dlt {number=272}{name=NORDIC_BLE}{display=nRF Sniffer for Bluetooth LE}") - - -def get_baud_rates(interface): - if not hasattr(serial, "__version__") or not serial.__version__.startswith("3."): - raise RuntimeError( - "Too old version of python 'serial' Library. Version 3 required." - ) - return UART.find_sniffer_baudrates(interface) - - -def get_interfaces(): - if not hasattr(serial, "__version__") or not serial.__version__.startswith("3."): - raise RuntimeError( - "Too old version of python 'serial' Library. Version 3 required." - ) - - devices = UART.find_sniffer() - return devices - - -def extcap_interfaces(): - """List available interfaces to capture from""" - print( - "extcap {version=%s}{display=nRF Sniffer for Bluetooth LE}" - "{help=https://www.nordicsemi.com/Software-and-Tools/Development-Tools/nRF-Sniffer-for-Bluetooth-LE}" - % Sniffer.VERSION_STRING - ) - - for interface_port in get_interfaces(): - if sys.platform == "win32": - print( - "interface {value=%s-%s}{display=nRF Sniffer for Bluetooth LE %s}" - % (interface_port, extcap_version, interface_port) - ) - else: - print( - "interface {value=%s-%s}{display=nRF Sniffer for Bluetooth LE}" - % (interface_port, extcap_version) - ) - - print( - "control {number=%d}{type=selector}{display=Device}{tooltip=Device list}" - % CTRL_ARG_DEVICE - ) - print( - "control {number=%d}{type=selector}{display=Key}{tooltip=}" % CTRL_ARG_KEY_TYPE - ) - print( - "control {number=%d}{type=string}{display=Value}" - "{tooltip=6 digit passkey or 16 or 32 bytes encryption key in hexadecimal starting with '0x', big endian format." - "If the entered key is shorter than 16 or 32 bytes, it will be zero-padded in front'}" - "{validation=\\b^(([0-9]{6})|(0x[0-9a-fA-F]{1,64})|([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}) (public|random))$\\b}" - % CTRL_ARG_KEY_VAL - ) - print( - "control {number=%d}{type=string}{display=Adv Hop}" - "{default=37,38,39}" - "{tooltip=Advertising channel hop sequence. " - "Change the order in which the sniffer switches advertising channels. " - "Valid channels are 37, 38 and 39 separated by comma.}" - r"{validation=^\s*((37|38|39)\s*,\s*){0,2}(37|38|39){1}\s*$}{required=true}" - % CTRL_ARG_ADVHOP - ) - print( - "control {number=%d}{type=button}{display=Clear}{tooltop=Clear or remove device from Device list}" - % CTRL_ARG_DEVICE_CLEAR - ) - print( - "control {number=%d}{type=button}{role=help}{display=Help}{tooltip=Access user guide (launches browser)}" - % CTRL_ARG_HELP - ) - print( - "control {number=%d}{type=button}{role=restore}{display=Defaults}{tooltip=Resets the user interface and clears the log file}" - % CTRL_ARG_RESTORE - ) - print( - "control {number=%d}{type=button}{role=logger}{display=Log}{tooltip=Log per interface}" - % CTRL_ARG_LOG - ) - - print( - "value {control=%d}{value= }{display=All advertising devices}{default=true}" - % CTRL_ARG_DEVICE - ) - print( - "value {control=%d}{value=%s}{display=Follow IRK}" - % (CTRL_ARG_DEVICE, zero_addr) - ) - - print( - "value {control=%d}{value=%d}{display=Legacy Passkey}{default=true}" - % (CTRL_ARG_KEY_TYPE, CTRL_KEY_TYPE_PASSKEY) - ) - print( - "value {control=%d}{value=%d}{display=Legacy OOB data}" - % (CTRL_ARG_KEY_TYPE, CTRL_KEY_TYPE_OOB) - ) - print( - "value {control=%d}{value=%d}{display=Legacy LTK}" - % (CTRL_ARG_KEY_TYPE, CTRL_KEY_TYPE_LEGACY_LTK) - ) - print( - "value {control=%d}{value=%d}{display=SC LTK}" - % (CTRL_ARG_KEY_TYPE, CTRL_KEY_TYPE_SC_LTK) - ) - print( - "value {control=%d}{value=%d}{display=SC Private Key}" - % (CTRL_ARG_KEY_TYPE, CTRL_KEY_TYPE_DH_PRIVATE_KEY) - ) - print( - "value {control=%d}{value=%d}{display=IRK}" - % (CTRL_ARG_KEY_TYPE, CTRL_KEY_TYPE_IRK) - ) - print( - "value {control=%d}{value=%d}{display=Add LE address}" - % (CTRL_ARG_KEY_TYPE, CTRL_KEY_TYPE_ADD_ADDR) - ) - print( - "value {control=%d}{value=%d}{display=Follow LE address}" - % (CTRL_ARG_KEY_TYPE, CTRL_KEY_TYPE_FOLLOW_ADDR) - ) - - -def string_address(address): - """Make a string representation of the address""" - if len(address) < 7: - return None - - addr_string = "" - - for i in range(5): - addr_string += format(address[i], "02x") + ":" - addr_string += format(address[5], "02x") + " " - - if address[6]: - addr_string += " random " - else: - addr_string += " public " - - return addr_string - - -def control_read(): - """Read a message from the control channel""" - header = fn_ctrl_in.read(6) - if not header: - # Ref. https://docs.python.org/3/tutorial/inputoutput.html#methods-of-file-objects: - # > If the end of the file has been reached, f.read() will return an - # > empty string ('') - return None, None, None - - _, _, length, arg, typ = struct.unpack(">sBHBB", header) - - payload = bytearray() - if length > 2: - payload = fn_ctrl_in.read(length - 2) - - return arg, typ, payload - - -def control_write(arg, typ, message): - """Write the message to the control channel""" - - if not fn_ctrl_out: - # No control out has been opened - return - - packet = bytearray() - packet += struct.pack(">BBHBB", ord("T"), 0, len(message) + 2, arg, typ) - packet += message.encode("utf-8") - - fn_ctrl_out.write(packet) - - -def capture_write(message): - """Write the message to the capture pipe""" - fn_capture.write(message) - fn_capture.flush() - - -def new_packet(notification): - """A new Bluetooth LE packet has arrived""" - if write_new_packets == True: - packet = notification.msg["packet"] - - if rssi_filter == 0 or in_follow_mode == True or packet.RSSI > rssi_filter: - p = bytes([packet.boardId] + packet.getList()) - capture_write(Pcap.create_packet(p, packet.time)) - - -def device_added(notification): - """A device is added or updated""" - device = notification.msg - - # Only add devices matching RSSI filter - if rssi_filter == 0 or device.RSSI > rssi_filter: - # Extcap selector uses \0 character to separate value and display value, - # therefore the display value cannot contain the \0 character as this - # would lead to truncation of the display value. - display = ( - device.name.replace("\0", "\\0") - + (" " + str(device.RSSI) + " dBm " if device.RSSI != 0 else " ") - + string_address(device.address) - ) - - message = str(device.address) + "\0" + display - - control_write(CTRL_ARG_DEVICE, CTRL_CMD_ADD, message) - - -def device_removed(notification): - """A device is removed""" - device = notification.msg - display = device.name + " " + string_address(device.address) - - message = "" - message += str(device.address) - - control_write(CTRL_ARG_DEVICE, CTRL_CMD_REMOVE, message) - logging.info("Removed: " + display) - - -def devices_cleared(notification): - """Devices have been cleared""" - message = "" - control_write(CTRL_ARG_DEVICE, CTRL_CMD_REMOVE, message) - - control_write(CTRL_ARG_DEVICE, CTRL_CMD_ADD, " " + "\0" + "All advertising devices") - control_write(CTRL_ARG_DEVICE, CTRL_CMD_ADD, zero_addr + "\0" + "Follow IRK") - control_write(CTRL_ARG_DEVICE, CTRL_CMD_SET, " ") - - -def handle_control_command(sniffer, arg, typ, payload): - """Handle command from control channel""" - global last_used_key_type - - if arg == CTRL_ARG_DEVICE: - if payload == b" ": - scan_for_devices(sniffer) - else: - values = payload - values = values.replace(b"[", b"") - values = values.replace(b"]", b"") - device_address = values.split(b",") - - logging.info("follow_device: {}".format(device_address)) - for i in range(6): - device_address[i] = int(device_address[i]) - - device_address[6] = 1 if device_address[6] == b" 1" else 0 - - device = Devices.Device(address=device_address, name='""', RSSI=0) - - follow_device(sniffer, device) - - elif arg == CTRL_ARG_DEVICE_CLEAR: - clear_devices(sniffer) - elif arg == CTRL_ARG_KEY_TYPE: - last_used_key_type = int(payload.decode("utf-8")) - elif arg == CTRL_ARG_KEY_VAL: - set_key_value(sniffer, payload) - elif arg == CTRL_ARG_ADVHOP: - set_advhop(sniffer, payload) - - -def control_read_initial_values(sniffer): - """Read initial control values""" - initialized = False - - while not initialized: - arg, typ, payload = control_read() - if typ == CTRL_CMD_INIT: - initialized = True - else: - handle_control_command(sniffer, arg, typ, payload) - - -def control_write_defaults(): - """Write default control values""" - control_write(CTRL_ARG_KEY_TYPE, CTRL_CMD_SET, str(last_used_key_type)) - control_write(CTRL_ARG_KEY_VAL, CTRL_CMD_SET, last_used_key_val) - control_write(CTRL_ARG_ADVHOP, CTRL_CMD_SET, last_used_advhop) - - -def scan_for_devices(sniffer): - """Start scanning for advertising devices""" - global in_follow_mode - if sniffer.state == 2: - log = "Scanning all advertising devices" - logging.info(log) - sniffer.scan(capture_scan_response, capture_scan_aux_pointer, capture_coded) - - in_follow_mode = False - - -def clear_devices(sniffer): - """Clear the advertising devices list""" - global in_follow_mode - - sniffer.clearDevices() - scan_for_devices(sniffer) - - in_follow_mode = False - - -def follow_device(sniffer, device): - """Follow the selected device""" - global write_new_packets, in_follow_mode - - sniffer.follow( - device, capture_only_advertising, capture_only_legacy_advertising, capture_coded - ) - time.sleep(0.1) - - in_follow_mode = True - logging.info("Following " + string_address(device.address)) - - -def set_key_value(sniffer, payload): - """Send key value to device""" - global last_used_key_val - - payload = payload.decode("utf-8") - last_used_key_val = payload - - if last_used_key_type == CTRL_KEY_TYPE_PASSKEY: - if re.match("^[0-9]{6}$", payload): - set_passkey(sniffer, payload) - else: - logging.info("Invalid key value: " + str(payload)) - elif last_used_key_type == CTRL_KEY_TYPE_OOB: - if re.match("^0[xX][0-9A-Za-z]{1,32}$", payload): - set_OOB(sniffer, payload[2:]) - else: - logging.info("Invalid key value: " + str(payload)) - elif last_used_key_type == CTRL_KEY_TYPE_DH_PRIVATE_KEY: - if re.match("^0[xX][0-9A-Za-z]{1,64}$", payload): - set_dh_private_key(sniffer, payload[2:]) - else: - logging.info("Invalid key value: " + str(payload)) - elif last_used_key_type == CTRL_KEY_TYPE_LEGACY_LTK: - if re.match("^0[xX][0-9A-Za-z]{1,32}$", payload): - set_legacy_ltk(sniffer, payload[2:]) - else: - logging.info("Invalid key value: " + str(payload)) - elif last_used_key_type == CTRL_KEY_TYPE_SC_LTK: - if re.match("^0[xX][0-9A-Za-z]{1,32}$", payload): - set_sc_ltk(sniffer, payload[2:]) - else: - logging.info("Invalid key value: " + str(payload)) - elif last_used_key_type == CTRL_KEY_TYPE_IRK: - if re.match("^0[xX][0-9A-Za-z]{1,32}$", payload): - set_irk(sniffer, payload[2:]) - else: - logging.info("Invalid key value: " + str(payload)) - elif last_used_key_type == CTRL_KEY_TYPE_ADD_ADDR: - if re.match( - "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}) (public|random)$", payload - ): - add_address(sniffer, payload) - else: - logging.info("Invalid key value: " + str(payload)) - elif last_used_key_type == CTRL_KEY_TYPE_FOLLOW_ADDR: - if re.match( - "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2}) (public|random)$", payload - ): - follow_address(sniffer, payload) - else: - logging.info("Invalid key value: " + str(payload)) - else: - logging.info("Invalid key type: " + str(last_used_key_type)) - - -def parse_hex(value): - if len(value) % 2 != 0: - value = "0" + value - - a = list(value) - return [int(x + y, 16) for x, y in zip(a[::2], a[1::2])] - - -def set_passkey(sniffer, payload): - """Send passkey to device""" - passkey = [] - logging.info("Setting Passkey: " + payload) - init_payload = int(payload, 10) - if len(payload) >= 6: - passkey = [] - passkey += [(init_payload >> 16) & 0xFF] - passkey += [(init_payload >> 8) & 0xFF] - passkey += [(init_payload >> 0) & 0xFF] - - sniffer.sendTK(passkey) - - -def set_OOB(sniffer, payload): - """Send OOB to device""" - logging.info("Setting OOB data: " + payload) - sniffer.sendTK(parse_hex(payload)) - - -def set_dh_private_key(sniffer, payload): - """Send Diffie-Hellman private key to device""" - logging.info("Setting DH private key: " + payload) - sniffer.sendPrivateKey(parse_hex(payload)) - - -def set_legacy_ltk(sniffer, payload): - """Send Legacy Long Term Key (LTK) to device""" - logging.info("Setting Legacy LTK: " + payload) - sniffer.sendLegacyLTK(parse_hex(payload)) - - -def set_sc_ltk(sniffer, payload): - """Send LE secure connections Long Term Key (LTK) to device""" - logging.info("Setting SC LTK: " + payload) - sniffer.sendSCLTK(parse_hex(payload)) - - -def set_irk(sniffer, payload): - """Send Identity Resolving Key (IRK) to device""" - logging.info("Setting IRK: " + payload) - sniffer.sendIRK(parse_hex(payload)) - - -def add_address(sniffer, payload): - """Add LE address to device list""" - logging.info("Adding LE address: " + payload) - - (addr, addr_type) = payload.split(" ") - device = [int(a, 16) for a in addr.split(":")] - - device.append(1 if addr_type == "random" else 0) - - new_device = Devices.Device(address=device, name='""', RSSI=0) - sniffer.addDevice(new_device) - - -def follow_address(sniffer, payload): - """Add LE address to device list""" - logging.info("Adding LE address: " + payload) - - (addr, addr_type) = payload.split(" ") - device = [int(a, 16) for a in addr.split(":")] - - device.append(1 if addr_type == "random" else 0) - - new_device = Devices.Device(address=device, name='""', RSSI=0) - sniffer.addDevice(new_device) - - control_write(CTRL_ARG_DEVICE, CTRL_CMD_SET, f"{new_device.address}") - follow_device(sniffer, new_device) - - -def set_advhop(sniffer, payload): - """Set advertising channel hop sequence""" - global last_used_advhop - - payload = payload.decode("utf-8") - - last_used_advhop = payload - - hops = [int(channel) for channel in payload.split(",")] - - sniffer.setAdvHopSequence(hops) - - log = "AdvHopSequence: " + str(hops) - logging.info(log) - - -def control_loop(sniffer): - """Main loop reading control messages""" - arg_read = CTRL_ARG_NONE - while arg_read is not None: - arg_read, typ, payload = control_read() - handle_control_command(sniffer, arg_read, typ, payload) - - -def error_interface_not_found(interface, fifo): - log = "nRF Sniffer for Bluetooth LE could not find interface: " + interface - control_write(CTRL_ARG_NONE, CTRL_CMD_ERROR_MSG, log) - extcap_close_fifo(fifo) - sys.exit(ERROR_INTERFACE) - - -def validate_interface(interface, fifo): - """Check if interface exists""" - if sys.platform != "win32" and not os.path.exists(interface): - error_interface_not_found(interface, fifo) - - -def get_default_baudrate(interface, fifo): - """Return the baud rate that interface is running at, or exit if the board is not found""" - rates = get_baud_rates(interface) - if rates is None: - error_interface_not_found(interface, fifo) - return rates["default"] - - -def get_supported_protocol_version(extcap_version): - """Return the maximum supported Packet Protocol Version""" - if extcap_version == "None": - return 2 - - (major, minor) = extcap_version.split(".") - - major = int(major) - minor = int(minor) - - if major > 3 or (major == 3 and minor >= 4): - return 3 - else: - return 2 - - -def setup_extcap_log_handler(): - """Add the a handler that emits log messages through the extcap control out channel""" - global extcap_log_handler - extcap_log_handler = ExtcapLoggerHandler() - Logger.addLogHandler(extcap_log_handler) - control_write(CTRL_ARG_LOG, CTRL_CMD_SET, "") - - -def teardown_extcap_log_handler(): - """Remove and reset the extcap log handler""" - global extcap_log_handler - if extcap_log_handler: - Logger.removeLogHandler(extcap_log_handler) - extcap_log_handler = None - - -def sniffer_capture(interface, baudrate, fifo, control_in, control_out): - """Start the sniffer to capture packets""" - global fn_capture, fn_ctrl_in, fn_ctrl_out, write_new_packets, extcap_log_handler - - try: - fn_capture = open(fifo, "wb", 0) - - if control_out is not None: - fn_ctrl_out = open(control_out, "wb", 0) - setup_extcap_log_handler() - - if control_in is not None: - fn_ctrl_in = open(control_in, "rb", 0) - - logging.info("Log started at %s", time.strftime("%c")) - - interface, extcap_version = interface.split("-") - logging.info("Extcap version %s", str(extcap_version)) - - capture_write(Pcap.get_global_header()) - validate_interface(interface, fifo) - if baudrate is None: - baudrate = get_default_baudrate(interface, fifo) - - sniffer = Sniffer.Sniffer(interface, baudrate) - sniffer.subscribe("NEW_BLE_PACKET", new_packet) - sniffer.subscribe("DEVICE_ADDED", device_added) - sniffer.subscribe("DEVICE_UPDATED", device_added) - sniffer.subscribe("DEVICE_REMOVED", device_removed) - sniffer.subscribe("DEVICES_CLEARED", devices_cleared) - sniffer.setAdvHopSequence([37, 38, 39]) - sniffer.setSupportedProtocolVersion( - get_supported_protocol_version(extcap_version) - ) - logging.info("Sniffer created") - - logging.info("Software version: %s" % sniffer.swversion) - sniffer.getFirmwareVersion() - sniffer.getTimestamp() - sniffer.start() - logging.info("sniffer started") - sniffer.scan(capture_scan_response, capture_scan_aux_pointer, capture_coded) - logging.info("scanning started") - - if fn_ctrl_in is not None and fn_ctrl_out is not None: - # First read initial control values - control_read_initial_values(sniffer) - - # Then write default values - control_write_defaults() - logging.info("defaults written") - - # Start receiving packets - write_new_packets = True - - # Start the control loop - logging.info("control loop") - control_loop(sniffer) - logging.info("exiting control loop") - - else: - logging.info("") - # Start receiving packets - write_new_packets = True - while True: - # Wait for keyboardinterrupt - pass - - except Exceptions.LockedException as e: - logging.info("{}".format(e.message)) - - except OSError: - # We'll get OSError=22 when/if wireshark kills the pipe(s) on capture - # stop. - pass - - finally: - # The first thing we should do is to tear down the extcap log handler. - # This might already have triggered an OSError, or we will trigger one - # by attempting to log at this point. - teardown_extcap_log_handler() - - # Safe to use logging again. - logging.info("Tearing down") - - sniffer.doExit() - if fn_capture is not None and not fn_capture.closed: - fn_capture.close() - - if fn_ctrl_in is not None and not fn_ctrl_in.closed: - fn_ctrl_in.close() - - if fn_ctrl_out is not None and not fn_ctrl_out.closed: - fn_ctrl_out.close() - - fn_capture = None - fn_ctrl_out = None - fn_ctrl_in = None - - logging.info("Exiting") - - -def extcap_close_fifo(fifo): - """ "Close extcap fifo""" - if not os.path.exists(fifo): - print("FIFO does not exist!", file=sys.stderr) - return - - # This is apparently needed to workaround an issue on Windows/macOS - # where the message cannot be read. (really?) - fh = open(fifo, "wb", 0) - fh.close() - - -class ExtcapLoggerHandler(logging.Handler): - """Handler used to display all logging messages in extcap""" - - def emit(self, record): - """Send log message to extcap""" - message = record.message.replace("\0", "\\0") - log_message = f"{record.levelname}: {message}\n" - control_write(CTRL_ARG_LOG, CTRL_CMD_ADD, log_message) - - -def parse_capture_filter(capture_filter): - """ "Parse given capture filter""" - global rssi_filter - m = re.search(r"^\s*rssi\s*(>=?)\s*(-?[0-9]+)\s*$", capture_filter, re.IGNORECASE) - if m: - rssi_filter = int(m.group(2)) - if rssi_filter > -10 or rssi_filter < -256: - print("Illegal RSSI value, must be between -10 and -256") - # Handle >= by modifying the threshold, since comparisons are always done with - # the > operator - if m.group(1) == ">=": - rssi_filter = rssi_filter - 1 - else: - print('Filter syntax: "RSSI >= -value"') - - -import atexit - - -@atexit.register -def goodbye(): - logging.info("Exiting PID {}".format(os.getpid())) - - -if __name__ == "__main__": - - # Capture options - parser = argparse.ArgumentParser( - description="Nordic Semiconductor nRF Sniffer for Bluetooth LE extcap plugin" - ) - - # Extcap Arguments - parser.add_argument("--capture", help="Start the capture", action="store_true") - - parser.add_argument( - "--extcap-interfaces", - help="List available interfaces to capture from", - action="store_true", - ) - - parser.add_argument("--extcap-interface", help="The interface to capture from") - - parser.add_argument( - "--extcap-dlts", help="List DLTs for the given interface", action="store_true" - ) - - parser.add_argument( - "--extcap-config", - help="List configurations for the given interface", - action="store_true", - ) - - parser.add_argument( - "--extcap-capture-filter", - help="Used together with capture to provide a capture filter", - ) - - parser.add_argument( - "--fifo", help="Use together with capture to provide the fifo to dump data to" - ) - - parser.add_argument( - "--extcap-control-in", - help="Used together with capture to get control messages from toolbar", - ) - - parser.add_argument( - "--extcap-control-out", - help="Used together with capture to send control messages to toolbar", - ) - - parser.add_argument("--extcap-version", help="Set extcap supported version") - - # Interface Arguments - parser.add_argument("--device", help="Device", default="") - parser.add_argument("--baudrate", type=int, help="The sniffer baud rate") - parser.add_argument( - "--only-advertising", help="Only advertising packets", action="store_true" - ) - parser.add_argument( - "--only-legacy-advertising", - help="Only legacy advertising packets", - action="store_true", - ) - parser.add_argument( - "--scan-follow-rsp", help="Find scan response data ", action="store_true" - ) - parser.add_argument( - "--scan-follow-aux", help="Find auxiliary pointer data", action="store_true" - ) - parser.add_argument( - "--coded", help="Scan and follow on LE Coded PHY", action="store_true" - ) - - logging.info("Started PID {}".format(os.getpid())) - - try: - args, unknown = parser.parse_known_args() - logging.info(args) - - except argparse.ArgumentError as exc: - print("%s" % exc, file=sys.stderr) - fifo_found = False - fifo = "" - for arg in sys.argv: - if arg == "--fifo" or arg == "--extcap-fifo": - fifo_found = True - elif fifo_found: - fifo = arg - break - extcap_close_fifo(fifo) - sys.exit(ERROR_ARG) - - if len(sys.argv) <= 1: - parser.exit("No arguments given!") - - if args.extcap_version: - extcap_version = args.extcap_version - - if args.extcap_capture_filter: - parse_capture_filter(args.extcap_capture_filter) - if args.extcap_interface and len(sys.argv) == 5: - sys.exit(0) - - if not args.extcap_interfaces and args.extcap_interface is None: - parser.exit("An interface must be provided or the selection must be displayed") - - if args.extcap_interfaces or args.extcap_interface is None: - extcap_interfaces() - sys.exit(0) - - if len(unknown) > 0: - print("Sniffer %d unknown arguments given" % len(unknown)) - logging.info("Sniffer %d unknown arguments given" % len(unknown)) - - interface = args.extcap_interface - - capture_only_advertising = args.only_advertising - capture_only_legacy_advertising = args.only_legacy_advertising - capture_scan_response = args.scan_follow_rsp - capture_scan_aux_pointer = args.scan_follow_aux - capture_coded = args.coded - - if args.extcap_config: - extcap_config(interface) - elif args.extcap_dlts: - extcap_dlts(interface) - elif args.capture: - if args.fifo is None: - parser.print_help() - sys.exit(ERROR_FIFO) - try: - logging.info("sniffer capture") - sniffer_capture( - interface, - args.baudrate, - args.fifo, - args.extcap_control_in, - args.extcap_control_out, - ) - except KeyboardInterrupt: - pass - except Exception as e: - import traceback - - logging.info(traceback.format_exc()) - logging.info("internal error: {}".format(repr(e))) - sys.exit(ERROR_INTERNAL) - else: - parser.print_help() - sys.exit(ERROR_USAGE) - logging.info("main exit PID {}".format(os.getpid())) From 8c720778bae51c5eb124efc441fd3b4a6f16a9a4 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Mon, 8 Dec 2025 22:00:00 +0100 Subject: [PATCH 28/33] Bump to Python 3.13 --- pkgs/myintercom-doorbell/default.nix | 5 ++++- pkgs/myintercom-doorbell/poetry.lock | 16 ++++++++-------- pkgs/myintercom-doorbell/pyproject.toml | 2 +- pkgs/myintercom-doorbell/shell.nix | 4 +++- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/pkgs/myintercom-doorbell/default.nix b/pkgs/myintercom-doorbell/default.nix index 37b3711..a333689 100644 --- a/pkgs/myintercom-doorbell/default.nix +++ b/pkgs/myintercom-doorbell/default.nix @@ -1,7 +1,10 @@ -{ poetry2nix }: +{ poetry2nix, python3 }: poetry2nix.mkPoetryApplication { pname = "myintercom-audiosocket"; version = "0.0.1"; projectDir = ./.; + propagatedBuildInputs = [ + python3.pkgs.audioop-lts + ]; } diff --git a/pkgs/myintercom-doorbell/poetry.lock b/pkgs/myintercom-doorbell/poetry.lock index 0ce0d9b..6c644ee 100644 --- a/pkgs/myintercom-doorbell/poetry.lock +++ b/pkgs/myintercom-doorbell/poetry.lock @@ -1,24 +1,24 @@ -# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. [[package]] name = "urllib3" -version = "2.5.0" +version = "2.6.1" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, - {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, + {file = "urllib3-2.6.1-py3-none-any.whl", hash = "sha256:e67d06fe947c36a7ca39f4994b08d73922d40e6cca949907be05efa6fd75110b"}, + {file = "urllib3-2.6.1.tar.gz", hash = "sha256:5379eb6e1aba4088bae84f8242960017ec8d8e3decf30480b3a1abdaa9671a3f"}, ] [package.extras] -brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +brotli = ["brotli (>=1.2.0) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=1.2.0.0) ; platform_python_implementation != \"CPython\""] h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [metadata] lock-version = "2.1" -python-versions = "^3.12" -content-hash = "a2502d4bca34c8c9ddc7579666a62dc15d3573a0240075cb566922a1d031831e" +python-versions = "^3.13" +content-hash = "33f69fba51a1d96af3dfe0957433b3a4c2f5baa5064ada3a95a640d65230416a" diff --git a/pkgs/myintercom-doorbell/pyproject.toml b/pkgs/myintercom-doorbell/pyproject.toml index 3a57dc6..d4442a2 100644 --- a/pkgs/myintercom-doorbell/pyproject.toml +++ b/pkgs/myintercom-doorbell/pyproject.toml @@ -7,7 +7,7 @@ readme = "README.md" packages = [{include = "myintercom_doorbell"}] [tool.poetry.dependencies] -python = "^3.12" +python = "^3.13" urllib3 = "^2.5.0" [tool.poetry.scripts] diff --git a/pkgs/myintercom-doorbell/shell.nix b/pkgs/myintercom-doorbell/shell.nix index cd52c53..0ee7dda 100644 --- a/pkgs/myintercom-doorbell/shell.nix +++ b/pkgs/myintercom-doorbell/shell.nix @@ -4,5 +4,7 @@ mkShell { buildInputs = [ poetry ]; - + propagatedBuildInputs = [ + python3.pkgs.audioop-lts + ]; } From e9bbfb3f75b5ff3ee79728b2399667bacf5c9e00 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 9 Dec 2025 15:32:40 +0100 Subject: [PATCH 29/33] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'disko': 'github:nix-community/disko/af087d076d3860760b3323f6b583f4d828c1ac17?narHash=sha256-TtcPgPmp2f0FAnc%2BDMEw4ardEgv1SGNR3/WFGH0N19M%3D' (2025-11-04) → 'github:nix-community/disko/8e68aa819d6a9964c8ac45172e68b943b597c52a?narHash=sha256-qw9iaIIz8D%2BlwsTO28VOaZBAJG97jH4%2Bci2pe7ZJR6Q%3D' (2025-12-09) • Updated input 'gomod2nix': 'github:nix-community/gomod2nix/7f8d7438f5870eb167abaf2c39eea3d2302019d1?narHash=sha256-pDyrtUQyeP1lVTMIYqJtftzDtsXEZaJjYy9ZQ/SGhL8%3D' (2025-10-09) → 'github:nix-community/gomod2nix/02e63a239d6eabd595db56852535992c898eba72?narHash=sha256-ur4QIAHwgFc0vXiaxn5No/FuZicxBr2p0gmT54xZkUQ%3D' (2025-11-24) • Updated input 'home-manager': 'github:nix-community/home-manager/2217780c39169a9c77915200137550c2ef0fa974?narHash=sha256-dhX2abFWxeXab3Aad4Pg1xGtn9W84/qetNXfmYUwktw%3D' (2025-11-26) → 'github:nix-community/home-manager/20561be440a11ec57a89715480717baf19fe6343?narHash=sha256-O8VTGey1xxiRW%2BFpb%2BPs9zU7ShmxUA1a7cMTcENCVNg%3D' (2025-12-08) • Updated input 'nix-pre-commit-hooks': 'github:cachix/git-hooks.nix/7275fa67fbbb75891c16d9dee7d88e58aea2d761?narHash=sha256-YG19IyrTdnVn0l3DvcUYm85u3PaqBt6tI6VvolcuHnA%3D' (2025-11-16) → 'github:cachix/git-hooks.nix/548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c?narHash=sha256-rhSqPNxDVow7OQKi4qS5H8Au0P4S3AYbawBSmJNUtBQ%3D' (2025-12-06) • Updated input 'nix-pre-commit-hooks/flake-compat': 'github:edolstra/flake-compat/9100a0f413b0c601e0533d1d94ffd501ce2e7885?narHash=sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX%2BfjA8Xf8PUmqCY%3D' (2025-05-12) → 'github:edolstra/flake-compat/f387cd2afec9419c8ee37694406ca490c3f34ee5?narHash=sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4%3D' (2025-10-27) • Updated input 'nixos-hardware': 'github:nixos/nixos-hardware/899dc449bc6428b9ee6b3b8f771ca2b0ef945ab9?narHash=sha256-BWWnUUT01lPwCWUvS0p6Px5UOBFeXJ8jR%2BZdLX8IbrU%3D' (2025-11-11) → 'github:nixos/nixos-hardware/9154f4569b6cdfd3c595851a6ba51bfaa472d9f3?narHash=sha256-ZlJTNLUKQRANlLDomuRWLBCH5792x%2B6XUJ4YdFRjtO4%3D' (2025-11-29) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f?narHash=sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD%2B/cTUzzgVFoaHrkqY%3D' (2025-11-30) → 'github:nixos/nixpkgs/d9bc5c7dceb30d8d6fafa10aeb6aa8a48c218454?narHash=sha256-y7RPKl/jJ/KAP/VKLMghMgXTlvNIJMHKskl8/Uuar7o%3D' (2025-12-06) • Updated input 'nixpkgsMaster': 'github:NixOS/nixpkgs/15901670689a6f338ebd2a9436b947ec189463a3?narHash=sha256-NzmsN8hRIn/9rJvZH3vPirBrOJJfeSfvPr4%2BfeeK7LY%3D' (2025-11-18) → 'github:NixOS/nixpkgs/fe21dc532562a038547185b77a488f4d7c9cbbda?narHash=sha256-S%2BvuUUBr4KoL1R8dx%2BM1xCsnbc75DelRucLFQX%2BTGxE%3D' (2025-12-09) • Updated input 'nur': 'github:nix-community/NUR/4c584dcedf9aa3394e9730e62693515a0e47674b?narHash=sha256-B1ua1UtkPuMwT8o4nOR7yNP5yz10usMcNnxwHpGtLck%3D' (2025-11-18) → 'github:nix-community/NUR/70540c989599d334e4e096e19ee707433a698882?narHash=sha256-aJpZaiYIzOHFi0AG0dbCwFYTGm95kkmEcWY5aSc1Wqc%3D' (2025-12-09) • Updated input 'nur/nixpkgs': 'github:nixos/nixpkgs/50a96edd8d0db6cc8db57dab6bb6d6ee1f3dc49a?narHash=sha256-Y7TDFPK4GlqrKrivOcsHG8xSGqQx3A6c%2Bi7novT85Uk%3D' (2025-11-16) → 'github:nixos/nixpkgs/f61125a668a320878494449750330ca58b78c557?narHash=sha256-BmPWzogsG2GsXZtlT%2BMTcAWeDK5hkbGRZTeZNW42fwA%3D' (2025-12-05) • Updated input 'sops-nix': 'github:Mic92/sops-nix/3f66a7fb9626a9a9c077612ef10a0ce396286c7d?narHash=sha256-n5xDOeNN%2BsmocQp3EMIc11IzBlR9wvvTIJZeL0g33Fs%3D' (2025-11-17) → 'github:Mic92/sops-nix/7fd1416aba1865eddcdec5bb11339b7222c2363e?narHash=sha256-qdBzo6puTgG4G2RHG0PkADg22ZnQo1JmSVFRxrD4QM4%3D' (2025-12-08) • Updated input 'vesc-tool': 'github:vedderb/vesc_tool/6a75051ce9742d97f14addd5d175ac516effb3c6?narHash=sha256-j%2BAZQYOuZ0X33p76LsZu4/NZl1Ccu6kkwPKC5HpIn1Y%3D' (2025-11-12) → 'github:vedderb/vesc_tool/7087fcabd5b0e193cb4a367477d352f0d51fdca0?narHash=sha256-/0i4g%2Bkiq9jdczpxX9Wjj5PSBYxDM6nqqmLKcwvY2sg%3D' (2025-12-03) --- flake.lock | 72 +++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/flake.lock b/flake.lock index 2ee5fbd..85335dc 100644 --- a/flake.lock +++ b/flake.lock @@ -65,11 +65,11 @@ ] }, "locked": { - "lastModified": 1762276996, - "narHash": "sha256-TtcPgPmp2f0FAnc+DMEw4ardEgv1SGNR3/WFGH0N19M=", + "lastModified": 1765270797, + "narHash": "sha256-qw9iaIIz8D+lwsTO28VOaZBAJG97jH4+ci2pe7ZJR6Q=", "owner": "nix-community", "repo": "disko", - "rev": "af087d076d3860760b3323f6b583f4d828c1ac17", + "rev": "8e68aa819d6a9964c8ac45172e68b943b597c52a", "type": "github" }, "original": { @@ -97,11 +97,11 @@ "flake-compat_2": { "flake": false, "locked": { - "lastModified": 1747046372, - "narHash": "sha256-CIVLLkVgvHYbgI2UpXvIIBJ12HWgX+fjA8Xf8PUmqCY=", + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", "owner": "edolstra", "repo": "flake-compat", - "rev": "9100a0f413b0c601e0533d1d94ffd501ce2e7885", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", "type": "github" }, "original": { @@ -243,11 +243,11 @@ ] }, "locked": { - "lastModified": 1759991118, - "narHash": "sha256-pDyrtUQyeP1lVTMIYqJtftzDtsXEZaJjYy9ZQ/SGhL8=", + "lastModified": 1763982521, + "narHash": "sha256-ur4QIAHwgFc0vXiaxn5No/FuZicxBr2p0gmT54xZkUQ=", "owner": "nix-community", "repo": "gomod2nix", - "rev": "7f8d7438f5870eb167abaf2c39eea3d2302019d1", + "rev": "02e63a239d6eabd595db56852535992c898eba72", "type": "github" }, "original": { @@ -263,11 +263,11 @@ ] }, "locked": { - "lastModified": 1764177491, - "narHash": "sha256-dhX2abFWxeXab3Aad4Pg1xGtn9W84/qetNXfmYUwktw=", + "lastModified": 1765170903, + "narHash": "sha256-O8VTGey1xxiRW+Fpb+Ps9zU7ShmxUA1a7cMTcENCVNg=", "owner": "nix-community", "repo": "home-manager", - "rev": "2217780c39169a9c77915200137550c2ef0fa974", + "rev": "20561be440a11ec57a89715480717baf19fe6343", "type": "github" }, "original": { @@ -386,11 +386,11 @@ ] }, "locked": { - "lastModified": 1763319842, - "narHash": "sha256-YG19IyrTdnVn0l3DvcUYm85u3PaqBt6tI6VvolcuHnA=", + "lastModified": 1765016596, + "narHash": "sha256-rhSqPNxDVow7OQKi4qS5H8Au0P4S3AYbawBSmJNUtBQ=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "7275fa67fbbb75891c16d9dee7d88e58aea2d761", + "rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c", "type": "github" }, "original": { @@ -402,11 +402,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1762847253, - "narHash": "sha256-BWWnUUT01lPwCWUvS0p6Px5UOBFeXJ8jR+ZdLX8IbrU=", + "lastModified": 1764440730, + "narHash": "sha256-ZlJTNLUKQRANlLDomuRWLBCH5792x+6XUJ4YdFRjtO4=", "owner": "nixos", "repo": "nixos-hardware", - "rev": "899dc449bc6428b9ee6b3b8f771ca2b0ef945ab9", + "rev": "9154f4569b6cdfd3c595851a6ba51bfaa472d9f3", "type": "github" }, "original": { @@ -418,11 +418,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1764522689, - "narHash": "sha256-SqUuBFjhl/kpDiVaKLQBoD8TLD+/cTUzzgVFoaHrkqY=", + "lastModified": 1764983851, + "narHash": "sha256-y7RPKl/jJ/KAP/VKLMghMgXTlvNIJMHKskl8/Uuar7o=", "owner": "nixos", "repo": "nixpkgs", - "rev": "8bb5646e0bed5dbd3ab08c7a7cc15b75ab4e1d0f", + "rev": "d9bc5c7dceb30d8d6fafa10aeb6aa8a48c218454", "type": "github" }, "original": { @@ -434,11 +434,11 @@ }, "nixpkgsMaster": { "locked": { - "lastModified": 1763473525, - "narHash": "sha256-NzmsN8hRIn/9rJvZH3vPirBrOJJfeSfvPr4+feeK7LY=", + "lastModified": 1765289907, + "narHash": "sha256-S+vuUUBr4KoL1R8dx+M1xCsnbc75DelRucLFQX+TGxE=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "15901670689a6f338ebd2a9436b947ec189463a3", + "rev": "fe21dc532562a038547185b77a488f4d7c9cbbda", "type": "github" }, "original": { @@ -466,11 +466,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1763283776, - "narHash": "sha256-Y7TDFPK4GlqrKrivOcsHG8xSGqQx3A6c+i7novT85Uk=", + "lastModified": 1764950072, + "narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=", "owner": "nixos", "repo": "nixpkgs", - "rev": "50a96edd8d0db6cc8db57dab6bb6d6ee1f3dc49a", + "rev": "f61125a668a320878494449750330ca58b78c557", "type": "github" }, "original": { @@ -502,11 +502,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1763471545, - "narHash": "sha256-B1ua1UtkPuMwT8o4nOR7yNP5yz10usMcNnxwHpGtLck=", + "lastModified": 1765284801, + "narHash": "sha256-aJpZaiYIzOHFi0AG0dbCwFYTGm95kkmEcWY5aSc1Wqc=", "owner": "nix-community", "repo": "NUR", - "rev": "4c584dcedf9aa3394e9730e62693515a0e47674b", + "rev": "70540c989599d334e4e096e19ee707433a698882", "type": "github" }, "original": { @@ -617,11 +617,11 @@ ] }, "locked": { - "lastModified": 1763417348, - "narHash": "sha256-n5xDOeNN+smocQp3EMIc11IzBlR9wvvTIJZeL0g33Fs=", + "lastModified": 1765231718, + "narHash": "sha256-qdBzo6puTgG4G2RHG0PkADg22ZnQo1JmSVFRxrD4QM4=", "owner": "Mic92", "repo": "sops-nix", - "rev": "3f66a7fb9626a9a9c077612ef10a0ce396286c7d", + "rev": "7fd1416aba1865eddcdec5bb11339b7222c2363e", "type": "github" }, "original": { @@ -712,11 +712,11 @@ "treefmt-nix": "treefmt-nix_2" }, "locked": { - "lastModified": 1762968599, - "narHash": "sha256-j+AZQYOuZ0X33p76LsZu4/NZl1Ccu6kkwPKC5HpIn1Y=", + "lastModified": 1764772762, + "narHash": "sha256-/0i4g+kiq9jdczpxX9Wjj5PSBYxDM6nqqmLKcwvY2sg=", "owner": "vedderb", "repo": "vesc_tool", - "rev": "6a75051ce9742d97f14addd5d175ac516effb3c6", + "rev": "7087fcabd5b0e193cb4a367477d352f0d51fdca0", "type": "github" }, "original": { From 7353eb481aeb830d245d555f7e8507f2eab794b6 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Tue, 9 Dec 2025 16:20:54 +0100 Subject: [PATCH 30/33] Use only post-quantum resistant algorithms --- modules/sshd.nix | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/sshd.nix b/modules/sshd.nix index 040ed09..0d02cb4 100644 --- a/modules/sshd.nix +++ b/modules/sshd.nix @@ -13,11 +13,8 @@ ]; # Use key exchange algorithms recommended by `nixpkgs#ssh-audit` KexAlgorithms = [ - "curve25519-sha256" - "curve25519-sha256@libssh.org" - "diffie-hellman-group16-sha512" - "diffie-hellman-group18-sha512" "sntrup761x25519-sha512@openssh.com" + "mlkem768x25519-sha256" ]; PasswordAuthentication = false; StreamLocalBindUnlink = true; # unbind gnupg sockets if they exists From 7a5d7c20ef17d5a0179b3cd41f31acf19c2fc33f Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Wed, 10 Dec 2025 17:19:18 +0100 Subject: [PATCH 31/33] Fix ipv6 prefix delegation Prefix delegation was broken after Vodafone swapped the plastic router. I'm not sure if this change is required tbh but I'll leave it like that as it works now. --- hosts/iron/configuration.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hosts/iron/configuration.nix b/hosts/iron/configuration.nix index 19eeef1..7b191f6 100644 --- a/hosts/iron/configuration.nix +++ b/hosts/iron/configuration.nix @@ -114,7 +114,7 @@ with lib; { interface ${interfaces.wan} ipv6rs ia_na 1 - ia_pd 1/::/64 ${interfaces.lan}/0/64 + ia_pd 2 ${interfaces.lan}/0 ''; jalr.luksUsbUnlock = { @@ -131,6 +131,7 @@ with lib; { boot = { kernel.sysctl = { "net.ipv6.conf.all.forwarding" = 1; + "net.ipv6.conf.enp0s25.accept_ra" = 1; }; initrd = { availableKernelModules = [ From 82ce9e9ac7a69d01c0747c0a48c992cc82b5a1d7 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Fri, 12 Dec 2025 13:00:03 +0100 Subject: [PATCH 32/33] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'disko': 'github:nix-community/disko/8e68aa819d6a9964c8ac45172e68b943b597c52a?narHash=sha256-qw9iaIIz8D%2BlwsTO28VOaZBAJG97jH4%2Bci2pe7ZJR6Q%3D' (2025-12-09) → 'github:nix-community/disko/d64e5cdca35b5fad7c504f615357a7afe6d9c49e?narHash=sha256-fTLX9kDwLr9Y0rH/nG%2Bh1XG5UU%2BjBcy0PFYn5eneRX8%3D' (2025-12-10) • Updated input 'home-manager': 'github:nix-community/home-manager/20561be440a11ec57a89715480717baf19fe6343?narHash=sha256-O8VTGey1xxiRW%2BFpb%2BPs9zU7ShmxUA1a7cMTcENCVNg%3D' (2025-12-08) → 'github:nix-community/home-manager/44777152652bc9eacf8876976fa72cc77ca8b9d8?narHash=sha256-FuFtkJrW1Z7u%2B3lhzPRau69E0CNjADku1mLQQflUORo%3D' (2025-12-10) • Updated input 'nix-pre-commit-hooks': 'github:cachix/git-hooks.nix/548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c?narHash=sha256-rhSqPNxDVow7OQKi4qS5H8Au0P4S3AYbawBSmJNUtBQ%3D' (2025-12-06) → 'github:cachix/git-hooks.nix/09e45f2598e1a8499c3594fe11ec2943f34fe509?narHash=sha256-dixPWKiHzh80PtD0aLuxYNQ0xP%2B843dfXG/yM3OzaYQ%3D' (2025-12-11) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/d9bc5c7dceb30d8d6fafa10aeb6aa8a48c218454?narHash=sha256-y7RPKl/jJ/KAP/VKLMghMgXTlvNIJMHKskl8/Uuar7o%3D' (2025-12-06) → 'github:nixos/nixpkgs/09eb77e94fa25202af8f3e81ddc7353d9970ac1b?narHash=sha256-mSD5Ob7a%2BT2RNjvPvOA1dkJHGVrNVl8ZOrAwBjKBDQo%3D' (2025-12-09) • Updated input 'nixpkgsMaster': 'github:NixOS/nixpkgs/fe21dc532562a038547185b77a488f4d7c9cbbda?narHash=sha256-S%2BvuUUBr4KoL1R8dx%2BM1xCsnbc75DelRucLFQX%2BTGxE%3D' (2025-12-09) → 'github:NixOS/nixpkgs/27225de9f2030213246e0d8d62957c43d5229368?narHash=sha256-HTHfcqG8WsrJG0aW3edXF5nQJK3VjPWcUTEi/r0LV7o%3D' (2025-12-12) • Updated input 'nur': 'github:nix-community/NUR/70540c989599d334e4e096e19ee707433a698882?narHash=sha256-aJpZaiYIzOHFi0AG0dbCwFYTGm95kkmEcWY5aSc1Wqc%3D' (2025-12-09) → 'github:nix-community/NUR/b4d99f4da68e9ffd29862904825730ba31a79406?narHash=sha256-hqGAGgmlYxwQufnYSS8E8wH7xyqLoaSIWGqZgdROkZg%3D' (2025-12-12) • Updated input 'nur/nixpkgs': 'github:nixos/nixpkgs/f61125a668a320878494449750330ca58b78c557?narHash=sha256-BmPWzogsG2GsXZtlT%2BMTcAWeDK5hkbGRZTeZNW42fwA%3D' (2025-12-05) → 'github:nixos/nixpkgs/addf7cf5f383a3101ecfba091b98d0a1263dc9b8?narHash=sha256-hM20uyap1a0M9d344I692r%2Bik4gTMyj60cQWO%2BhAYP8%3D' (2025-12-08) --- flake.lock | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/flake.lock b/flake.lock index 85335dc..c5852ed 100644 --- a/flake.lock +++ b/flake.lock @@ -65,11 +65,11 @@ ] }, "locked": { - "lastModified": 1765270797, - "narHash": "sha256-qw9iaIIz8D+lwsTO28VOaZBAJG97jH4+ci2pe7ZJR6Q=", + "lastModified": 1765326679, + "narHash": "sha256-fTLX9kDwLr9Y0rH/nG+h1XG5UU+jBcy0PFYn5eneRX8=", "owner": "nix-community", "repo": "disko", - "rev": "8e68aa819d6a9964c8ac45172e68b943b597c52a", + "rev": "d64e5cdca35b5fad7c504f615357a7afe6d9c49e", "type": "github" }, "original": { @@ -263,11 +263,11 @@ ] }, "locked": { - "lastModified": 1765170903, - "narHash": "sha256-O8VTGey1xxiRW+Fpb+Ps9zU7ShmxUA1a7cMTcENCVNg=", + "lastModified": 1765384171, + "narHash": "sha256-FuFtkJrW1Z7u+3lhzPRau69E0CNjADku1mLQQflUORo=", "owner": "nix-community", "repo": "home-manager", - "rev": "20561be440a11ec57a89715480717baf19fe6343", + "rev": "44777152652bc9eacf8876976fa72cc77ca8b9d8", "type": "github" }, "original": { @@ -386,11 +386,11 @@ ] }, "locked": { - "lastModified": 1765016596, - "narHash": "sha256-rhSqPNxDVow7OQKi4qS5H8Au0P4S3AYbawBSmJNUtBQ=", + "lastModified": 1765464257, + "narHash": "sha256-dixPWKiHzh80PtD0aLuxYNQ0xP+843dfXG/yM3OzaYQ=", "owner": "cachix", "repo": "git-hooks.nix", - "rev": "548fc44fca28a5e81c5d6b846e555e6b9c2a5a3c", + "rev": "09e45f2598e1a8499c3594fe11ec2943f34fe509", "type": "github" }, "original": { @@ -418,11 +418,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1764983851, - "narHash": "sha256-y7RPKl/jJ/KAP/VKLMghMgXTlvNIJMHKskl8/Uuar7o=", + "lastModified": 1765311797, + "narHash": "sha256-mSD5Ob7a+T2RNjvPvOA1dkJHGVrNVl8ZOrAwBjKBDQo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "d9bc5c7dceb30d8d6fafa10aeb6aa8a48c218454", + "rev": "09eb77e94fa25202af8f3e81ddc7353d9970ac1b", "type": "github" }, "original": { @@ -434,11 +434,11 @@ }, "nixpkgsMaster": { "locked": { - "lastModified": 1765289907, - "narHash": "sha256-S+vuUUBr4KoL1R8dx+M1xCsnbc75DelRucLFQX+TGxE=", + "lastModified": 1765536405, + "narHash": "sha256-HTHfcqG8WsrJG0aW3edXF5nQJK3VjPWcUTEi/r0LV7o=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "fe21dc532562a038547185b77a488f4d7c9cbbda", + "rev": "27225de9f2030213246e0d8d62957c43d5229368", "type": "github" }, "original": { @@ -466,11 +466,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1764950072, - "narHash": "sha256-BmPWzogsG2GsXZtlT+MTcAWeDK5hkbGRZTeZNW42fwA=", + "lastModified": 1765186076, + "narHash": "sha256-hM20uyap1a0M9d344I692r+ik4gTMyj60cQWO+hAYP8=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f61125a668a320878494449750330ca58b78c557", + "rev": "addf7cf5f383a3101ecfba091b98d0a1263dc9b8", "type": "github" }, "original": { @@ -502,11 +502,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1765284801, - "narHash": "sha256-aJpZaiYIzOHFi0AG0dbCwFYTGm95kkmEcWY5aSc1Wqc=", + "lastModified": 1765540078, + "narHash": "sha256-hqGAGgmlYxwQufnYSS8E8wH7xyqLoaSIWGqZgdROkZg=", "owner": "nix-community", "repo": "NUR", - "rev": "70540c989599d334e4e096e19ee707433a698882", + "rev": "b4d99f4da68e9ffd29862904825730ba31a79406", "type": "github" }, "original": { From 81cbb02774948400184a934879982c89ec470129 Mon Sep 17 00:00:00 2001 From: Jakob Lechner Date: Fri, 12 Dec 2025 13:05:02 +0100 Subject: [PATCH 33/33] Add Resynthesizer plugin to GIMP --- users/jalr/modules/graphics/gimp.nix | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/users/jalr/modules/graphics/gimp.nix b/users/jalr/modules/graphics/gimp.nix index c64e108..bb318b7 100644 --- a/users/jalr/modules/graphics/gimp.nix +++ b/users/jalr/modules/graphics/gimp.nix @@ -1,7 +1,13 @@ { nixosConfig, lib, pkgs, ... }: lib.mkIf nixosConfig.jalr.gui.enable { - home.packages = with pkgs; [ - gimp + home.packages = [ + ( + pkgs.gimp-with-plugins.override { + plugins = with pkgs.gimpPlugins; [ + resynthesizer + ]; + } + ) ]; }