mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-17 19:21:04 +00:00
Merge pull request #290008 from eum3l/add-opengfw
opengfw: init at 0.4.0 (+NixOS module)
This commit is contained in:
commit
81cb83b07f
|
@ -6239,6 +6239,12 @@
|
|||
githubId = 2147649;
|
||||
name = "Euan Kemp";
|
||||
};
|
||||
eum3l = {
|
||||
email = "eum3l@proton.me";
|
||||
githubId = 77971322;
|
||||
github = "eum3l";
|
||||
name = "Emil";
|
||||
};
|
||||
eureka-cpu = {
|
||||
email = "github.eureka@gmail.com";
|
||||
github = "eureka-cpu";
|
||||
|
|
|
@ -60,6 +60,8 @@
|
|||
|
||||
- [Improved File Manager](https://github.com/misterunknown/ifm), or IFM, a single-file web-based file manager.
|
||||
|
||||
- [OpenGFW](https://github.com/apernet/OpenGFW), an implementation of the Great Firewall on Linux. Available as [services.opengfw](#opt-services.opengfw.enable).
|
||||
|
||||
## Backward Incompatibilities {#sec-release-24.11-incompatibilities}
|
||||
|
||||
- `transmission` package has been aliased with a `trace` warning to `transmission_3`. Since [Transmission 4 has been released last year](https://github.com/transmission/transmission/releases/tag/4.0.0), and Transmission 3 will eventually go away, it was decided perform this warning alias to make people aware of the new version. The `services.transmission.package` defaults to `transmission_3` as well because the upgrade can cause data loss in certain specific usage patterns (examples: [#5153](https://github.com/transmission/transmission/issues/5153), [#6796](https://github.com/transmission/transmission/issues/6796)). Please make sure to back up to your data directory per your usage:
|
||||
|
|
|
@ -1137,6 +1137,7 @@
|
|||
./services/networking/oink.nix
|
||||
./services/networking/onedrive.nix
|
||||
./services/networking/openconnect.nix
|
||||
./services/networking/opengfw.nix
|
||||
./services/networking/openvpn.nix
|
||||
./services/networking/ostinato.nix
|
||||
./services/networking/owamp.nix
|
||||
|
|
414
nixos/modules/services/networking/opengfw.nix
Normal file
414
nixos/modules/services/networking/opengfw.nix
Normal file
|
@ -0,0 +1,414 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib)
|
||||
mkOption
|
||||
types
|
||||
mkIf
|
||||
optionalString
|
||||
;
|
||||
cfg = config.services.opengfw;
|
||||
in
|
||||
{
|
||||
options.services.opengfw = {
|
||||
enable = lib.mkEnableOption ''
|
||||
OpenGFW, A flexible, easy-to-use, open source implementation of GFW on Linux
|
||||
'';
|
||||
|
||||
package = lib.mkPackageOption pkgs "opengfw" { default = "opengfw"; };
|
||||
|
||||
user = mkOption {
|
||||
default = "opengfw";
|
||||
type = types.singleLineStr;
|
||||
description = "Username of the OpenGFW user.";
|
||||
};
|
||||
|
||||
dir = mkOption {
|
||||
default = "/var/lib/opengfw";
|
||||
type = types.singleLineStr;
|
||||
description = ''
|
||||
Working directory of the OpenGFW service and home of `opengfw.user`.
|
||||
'';
|
||||
};
|
||||
|
||||
logFile = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.path;
|
||||
example = "/var/lib/opengfw/opengfw.log";
|
||||
description = ''
|
||||
File to write the output to instead of systemd.
|
||||
'';
|
||||
};
|
||||
|
||||
logFormat = mkOption {
|
||||
description = ''
|
||||
Format of the logs. [logFormatMap](https://github.com/apernet/OpenGFW/blob/d7737e92117a11c9a6100d53019fac3b9d724fe3/cmd/root.go#L62)
|
||||
'';
|
||||
default = "json";
|
||||
example = "console";
|
||||
type = types.enum [
|
||||
"json"
|
||||
"console"
|
||||
];
|
||||
};
|
||||
|
||||
pcapReplay = mkOption {
|
||||
default = null;
|
||||
example = "./opengfw.pcap";
|
||||
type = types.nullOr types.path;
|
||||
description = ''
|
||||
Path to PCAP replay file.
|
||||
In pcap mode, none of the actions in the rules have any effect.
|
||||
This mode is mainly for debugging.
|
||||
'';
|
||||
};
|
||||
|
||||
logLevel = mkOption {
|
||||
description = ''
|
||||
Level of the logs. [logLevelMap](https://github.com/apernet/OpenGFW/blob/d7737e92117a11c9a6100d53019fac3b9d724fe3/cmd/root.go#L55)
|
||||
'';
|
||||
default = "info";
|
||||
example = "warn";
|
||||
type = types.enum [
|
||||
"debug"
|
||||
"info"
|
||||
"warn"
|
||||
"error"
|
||||
];
|
||||
};
|
||||
|
||||
rulesFile = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.path;
|
||||
description = ''
|
||||
Path to file containing OpenGFW rules.
|
||||
'';
|
||||
};
|
||||
|
||||
settingsFile = mkOption {
|
||||
default = null;
|
||||
type = types.nullOr types.path;
|
||||
description = ''
|
||||
Path to file containing OpenGFW settings.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
default = null;
|
||||
description = ''
|
||||
Settings passed to OpenGFW. [Example config](https://gfw.dev/docs/build-run/#config-example)
|
||||
'';
|
||||
type = types.nullOr (
|
||||
types.submodule {
|
||||
options = {
|
||||
replay = mkOption {
|
||||
description = ''
|
||||
PCAP replay settings.
|
||||
'';
|
||||
default = { };
|
||||
type = types.submodule {
|
||||
options = {
|
||||
realtime = mkOption {
|
||||
description = ''
|
||||
Whether the packets in the PCAP file should be replayed in "real time" (instead of as fast as possible).
|
||||
'';
|
||||
default = false;
|
||||
example = true;
|
||||
type = types.bool;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
io = mkOption {
|
||||
description = ''
|
||||
IO settings.
|
||||
'';
|
||||
default = { };
|
||||
type = types.submodule {
|
||||
options = {
|
||||
queueSize = mkOption {
|
||||
description = "IO queue size.";
|
||||
type = types.int;
|
||||
default = 1024;
|
||||
example = 2048;
|
||||
};
|
||||
local = mkOption {
|
||||
description = ''
|
||||
Set to false if you want to run OpenGFW on FORWARD chain. (e.g. on a router)
|
||||
'';
|
||||
type = types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
};
|
||||
rst = mkOption {
|
||||
description = ''
|
||||
Set to true if you want to send RST for blocked TCP connections, needs `local = false`.
|
||||
'';
|
||||
type = types.bool;
|
||||
default = !cfg.settings.io.local;
|
||||
defaultText = "`!config.services.opengfw.settings.io.local`";
|
||||
example = false;
|
||||
};
|
||||
rcvBuf = mkOption {
|
||||
description = "Netlink receive buffer size.";
|
||||
type = types.int;
|
||||
default = 4194304;
|
||||
example = 2097152;
|
||||
};
|
||||
sndBuf = mkOption {
|
||||
description = "Netlink send buffer size.";
|
||||
type = types.int;
|
||||
default = 4194304;
|
||||
example = 2097152;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
ruleset = mkOption {
|
||||
description = ''
|
||||
The path to load specific local geoip/geosite db files.
|
||||
If not set, they will be automatically downloaded from (Loyalsoldier/v2ray-rules-dat)[https://github.com/Loyalsoldier/v2ray-rules-dat].
|
||||
'';
|
||||
default = { };
|
||||
type = types.submodule {
|
||||
options = {
|
||||
geoip = mkOption {
|
||||
description = "Path to `geoip.dat`.";
|
||||
default = null;
|
||||
type = types.nullOr types.path;
|
||||
};
|
||||
geosite = mkOption {
|
||||
description = "Path to `geosite.dat`.";
|
||||
default = null;
|
||||
type = types.nullOr types.path;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
workers = mkOption {
|
||||
default = { };
|
||||
description = "Worker settings.";
|
||||
type = types.submodule {
|
||||
options = {
|
||||
count = mkOption {
|
||||
type = types.int;
|
||||
description = ''
|
||||
Number of workers.
|
||||
Recommended to be no more than the number of CPU cores
|
||||
'';
|
||||
default = 4;
|
||||
example = 8;
|
||||
};
|
||||
queueSize = mkOption {
|
||||
type = types.int;
|
||||
description = "Worker queue size.";
|
||||
default = 16;
|
||||
example = 32;
|
||||
};
|
||||
tcpMaxBufferedPagesTotal = mkOption {
|
||||
type = types.int;
|
||||
description = ''
|
||||
TCP max total buffered pages.
|
||||
'';
|
||||
default = 4096;
|
||||
example = 8192;
|
||||
};
|
||||
tcpMaxBufferedPagesPerConn = mkOption {
|
||||
type = types.int;
|
||||
description = ''
|
||||
TCP max total bufferd pages per connection.
|
||||
'';
|
||||
default = 64;
|
||||
example = 128;
|
||||
};
|
||||
tcpTimeout = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
How long a connection is considered dead when no data is being transferred.
|
||||
Dead connections are purged from TCP reassembly pools once per minute.
|
||||
'';
|
||||
default = "10m";
|
||||
example = "5m";
|
||||
};
|
||||
udpMaxStreams = mkOption {
|
||||
type = types.int;
|
||||
description = "UDP max streams.";
|
||||
default = 4096;
|
||||
example = 8192;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
rules = mkOption {
|
||||
default = [ ];
|
||||
description = ''
|
||||
Rules passed to OpenGFW. [Example rules](https://gfw.dev/docs/rules)
|
||||
'';
|
||||
type = types.listOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
description = "Name of the rule.";
|
||||
example = "block google dns";
|
||||
type = types.singleLineStr;
|
||||
};
|
||||
|
||||
action = mkOption {
|
||||
description = ''
|
||||
Action of the rule. [Supported actions](https://gfw.dev/docs/rules#supported-actions)
|
||||
'';
|
||||
default = "allow";
|
||||
example = "block";
|
||||
type = types.enum [
|
||||
"allow"
|
||||
"block"
|
||||
"drop"
|
||||
"modify"
|
||||
];
|
||||
};
|
||||
|
||||
log = mkOption {
|
||||
description = "Whether to enable logging for the rule.";
|
||||
default = true;
|
||||
example = false;
|
||||
type = types.bool;
|
||||
};
|
||||
|
||||
expr = mkOption {
|
||||
description = ''
|
||||
[Expr Language](https://expr-lang.org/docs/language-definition) expression using [analyzers](https://gfw.dev/docs/analyzers) and [functions](https://gfw.dev/docs/functions).
|
||||
'';
|
||||
type = types.str;
|
||||
example = ''dns != nil && dns.qr && any(dns.questions, {.name endsWith "google.com"})'';
|
||||
};
|
||||
|
||||
modifier = mkOption {
|
||||
default = null;
|
||||
description = ''
|
||||
Modification of specified packets when using the `modify` action. [Available modifiers](https://github.com/apernet/OpenGFW/tree/master/modifier)
|
||||
'';
|
||||
type = types.nullOr (
|
||||
types.submodule {
|
||||
options = {
|
||||
name = mkOption {
|
||||
description = "Name of the modifier.";
|
||||
type = types.singleLineStr;
|
||||
example = "dns";
|
||||
};
|
||||
|
||||
args = mkOption {
|
||||
description = "Arguments passed to the modifier.";
|
||||
type = types.attrs;
|
||||
example = {
|
||||
a = "0.0.0.0";
|
||||
aaaa = "::";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
example = [
|
||||
{
|
||||
name = "block v2ex http";
|
||||
action = "block";
|
||||
expr = ''string(http?.req?.headers?.host) endsWith "v2ex.com"'';
|
||||
}
|
||||
{
|
||||
name = "block google socks";
|
||||
action = "block";
|
||||
expr = ''string(socks?.req?.addr) endsWith "google.com" && socks?.req?.port == 80'';
|
||||
}
|
||||
{
|
||||
name = "v2ex dns poisoning";
|
||||
action = "modify";
|
||||
modifier = {
|
||||
name = "dns";
|
||||
args = {
|
||||
a = "0.0.0.0";
|
||||
aaaa = "::";
|
||||
};
|
||||
};
|
||||
expr = ''dns != nil && dns.qr && any(dns.questions, {.name endsWith "v2ex.com"})'';
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
format = pkgs.formats.yaml { };
|
||||
|
||||
settings =
|
||||
if cfg.settings != null then
|
||||
format.generate "opengfw-config.yaml" cfg.settings
|
||||
else
|
||||
cfg.settingsFile;
|
||||
rules = if cfg.rules != [ ] then format.generate "opengfw-rules.yaml" cfg.rules else cfg.rulesFile;
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
security.wrappers.OpenGFW = {
|
||||
owner = cfg.user;
|
||||
group = cfg.user;
|
||||
capabilities = "cap_net_admin+ep";
|
||||
source = "${cfg.package}/bin/OpenGFW";
|
||||
};
|
||||
|
||||
systemd.services.opengfw = {
|
||||
description = "OpenGFW";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
path = with pkgs; [ iptables ];
|
||||
|
||||
preStart = ''
|
||||
${optionalString (rules != null) "ln -sf ${rules} rules.yaml"}
|
||||
${optionalString (settings != null) "ln -sf ${settings} config.yaml"}
|
||||
'';
|
||||
|
||||
script = ''
|
||||
${config.security.wrapperDir}/OpenGFW \
|
||||
-f ${cfg.logFormat} \
|
||||
-l ${cfg.logLevel} \
|
||||
${optionalString (cfg.pcapReplay != null) "-p ${cfg.pcapReplay}"} \
|
||||
-c config.yaml \
|
||||
rules.yaml
|
||||
'';
|
||||
|
||||
serviceConfig = rec {
|
||||
WorkingDirectory = cfg.dir;
|
||||
ExecReload = "kill -HUP $MAINPID";
|
||||
Restart = "always";
|
||||
User = cfg.user;
|
||||
StandardOutput = mkIf (cfg.logFile != null) "append:${cfg.logFile}";
|
||||
StandardError = StandardOutput;
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
groups.${cfg.user} = { };
|
||||
users.${cfg.user} = {
|
||||
description = "opengfw user";
|
||||
isSystemUser = true;
|
||||
group = cfg.user;
|
||||
home = cfg.dir;
|
||||
createHome = true;
|
||||
homeMode = "750";
|
||||
};
|
||||
};
|
||||
};
|
||||
meta.maintainers = with lib.maintainers; [ eum3l ];
|
||||
}
|
37
pkgs/by-name/op/opengfw/package.nix
Normal file
37
pkgs/by-name/op/opengfw/package.nix
Normal file
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
lib,
|
||||
buildGoModule,
|
||||
fetchFromGitHub,
|
||||
}:
|
||||
let
|
||||
pname = "opengfw";
|
||||
version = "0.4.0";
|
||||
in
|
||||
buildGoModule {
|
||||
inherit pname version;
|
||||
CGO_ENABLED = 0;
|
||||
vendorHash = "sha256-F8jTvgxOhOGVtl6B8u0xAIvjNwVjBtvAhApzjIgykpY=";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "apernet";
|
||||
repo = "opengfw";
|
||||
rev = "refs/tags/v${version}";
|
||||
hash = "sha256-kmbG6l5CtZGM/zpvl2pukq5xsOIy28RDyb4sHBsoyOw=";
|
||||
};
|
||||
|
||||
meta = {
|
||||
mainProgram = "OpenGFW";
|
||||
description = "Flexible, easy-to-use, open source implementation of GFW on Linux";
|
||||
longDescription = ''
|
||||
OpenGFW is your very own DIY Great Firewall of China, available as a flexible,
|
||||
easy-to-use open source program on Linux. Why let the powers that be have all the fun?
|
||||
It's time to give power to the people and democratize censorship.
|
||||
Bring the thrill of cyber-sovereignty right into your home router
|
||||
and start filtering like a pro - you too can play Big Brother.
|
||||
'';
|
||||
homepage = "https://gfw.dev/";
|
||||
license = lib.licenses.mpl20;
|
||||
platforms = lib.platforms.linux;
|
||||
maintainers = with lib.maintainers; [ eum3l ];
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue