Skip to content

Commit

Permalink
Merge pull request #974 from enesoztrk/chromecast
Browse files Browse the repository at this point in the history
Chromecast support
  • Loading branch information
brianmcgillion authored Jan 31, 2025
2 parents e20addd + e772a89 commit 88a2ef8
Show file tree
Hide file tree
Showing 11 changed files with 443 additions and 70 deletions.
10 changes: 7 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
treefmt-nix.follows = "treefmt-nix";
pre-commit-hooks-nix.follows = "git-hooks-nix";
flake-compat.follows = "flake-compat";
crane.follows = "givc/crane";
};
};

Expand Down
11 changes: 11 additions & 0 deletions modules/microvm/virtualization/microvm/netvm.nix
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,17 @@ let
networking = {
firewall.allowedTCPPorts = [ 53 ];
firewall.allowedUDPPorts = [ 53 ];
firewall.extraCommands = lib.mkAfter ''
# Set the default policies
iptables -P INPUT DROP
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
# Allow loopback traffic
iptables -I INPUT -i lo -j ACCEPT
iptables -I OUTPUT -o lo -j ACCEPT
'';
};

# WORKAROUND: Create a rule to temporary hardcode device name for Wi-Fi adapter on x86
Expand Down
6 changes: 6 additions & 0 deletions modules/reference/appvms/google-chrome.nix
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
ghaf.reference.programs.google-chrome.enable = true;
ghaf.services.xdghandlers.enable = true;
ghaf.security.apparmor.enable = true;

networking = {
firewall.allowedUDPPorts = config.ghaf.reference.services.chromecast.udpPorts;
firewall.allowedTCPPorts = config.ghaf.reference.services.chromecast.tcpPorts;

};
}
];
}
Expand Down
1 change: 1 addition & 0 deletions modules/reference/profiles/mvp-user-trial.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ in
enable = true;
dendrite = true;
proxy-business = lib.mkForce config.ghaf.reference.appvms.business-vm;
google-chromecast = true;
};

personalize = {
Expand Down
31 changes: 31 additions & 0 deletions modules/reference/services/chromecast/chromecast-config.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Copyright 2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
{ config, lib, ... }:
{
config.ghaf.reference.services.chromecast =
let
externalNic =
let
firstPciWifiDevice = lib.head config.ghaf.hardware.definition.network.pciDevices;
in
"${firstPciWifiDevice.name}";

internalNic =
let
vmNetworking = import ../../../microvm/virtualization/microvm/common/vm-networking.nix {
inherit config;
inherit lib;
vmName = "net-vm";
inherit (config.microvm.net-vm) macAddress;
internalIP = 1;
};
in
"${lib.head vmNetworking.networking.nat.internalInterfaces}";

in
{
enable = lib.mkDefault false;
inherit externalNic;
inherit internalNic;
};
}
118 changes: 118 additions & 0 deletions modules/reference/services/chromecast/chromecast.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Copyright 2024 TII (SSRC) and the Ghaf contributors
# SPDX-License-Identifier: Apache-2.0
{
config,
lib,
...
}:
let
cfg = config.ghaf.reference.services.chromecast;
inherit (config.ghaf.reference) services;
inherit (lib)
mkEnableOption
mkOption
mkIf
types
;
tcpChromeCastPort1 = 8008;
tcpChromeCastPort2 = 8009;

ssdpMcastPort = 1900;
mdnsMcastPort = 5353;
ssdpMcastIp = "239.255.255.250";
in
{
options.ghaf.reference.services.chromecast = {
enable = mkEnableOption "Enable chromecast service";

externalNic = mkOption {
type = types.str;
default = "";
description = ''
External network interface
'';
};
internalNic = mkOption {
type = types.str;
default = "";
description = ''
Internal network interface
'';
};

tcpPorts = mkOption {
type = lib.types.listOf lib.types.port;
readOnly = true;

default = [
tcpChromeCastPort1
tcpChromeCastPort2
];
description = ''
Chromecast tcp ports
'';
};
udpPorts = mkOption {
type = lib.types.listOf lib.types.port;
readOnly = true;
default = [
ssdpMcastPort
mdnsMcastPort
];
description = ''
Chromecast udp ports
'';
};
};

config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.externalNic != "";
message = "External Nic must be set";
}
{
assertion = cfg.internalNic != "";
message = "Internal Nic must be set";
}
];

services.nw-packet-forwarder = {
enable = true;
inherit (cfg) externalNic;
inherit (cfg) internalNic;
chromecast = true;
};

services.smcroute = {
enable = true;
bindingNic = "${cfg.externalNic}";
rules = ''
mgroup from ${cfg.externalNic} group ${ssdpMcastIp}
mgroup from ${cfg.internalNic} group ${ssdpMcastIp}
mroute from ${cfg.externalNic} group ${ssdpMcastIp} to ${cfg.internalNic}
mroute from ${cfg.internalNic} group ${ssdpMcastIp} to ${cfg.externalNic}
'';
};
networking = {
firewall.enable = true;
firewall.extraCommands = "
# Forward incoming TCP traffic on ports 8008 and 8009 to the internal NIC
iptables -I FORWARD -i ${cfg.externalNic} -o ${cfg.internalNic} -p tcp --sport ${toString tcpChromeCastPort1} -j ACCEPT
iptables -I FORWARD -i ${cfg.externalNic} -o ${cfg.internalNic} -p tcp --sport ${toString tcpChromeCastPort2} -j ACCEPT
# Enable NAT for outgoing 8008 and 8009 Chromecast traffic
iptables -t nat -I POSTROUTING -o ${cfg.externalNic} -p tcp --dport ${toString tcpChromeCastPort1} -j MASQUERADE
iptables -t nat -I POSTROUTING -o ${cfg.externalNic} -p tcp --dport ${toString tcpChromeCastPort2} -j MASQUERADE
# TTL adjustments to avoid multicast loops
iptables -t mangle -I PREROUTING -i ${cfg.externalNic} -d ${ssdpMcastIp} -j TTL --ttl-set 1
iptables -t mangle -I PREROUTING -i ${cfg.internalNic} -d ${ssdpMcastIp} -j TTL --ttl-inc 1
# Enable NAT for outgoing udp multicast traffic
iptables -t nat -I POSTROUTING -o ${cfg.externalNic} -p udp -d ${ssdpMcastIp} --dport ${toString ssdpMcastPort} -j MASQUERADE
";

};
};
}
7 changes: 7 additions & 0 deletions modules/reference/services/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,25 @@ in
./dendrite-pinecone/dendrite-pinecone.nix
./dendrite-pinecone/dendrite-config.nix
./proxy-server/3proxy-config.nix
./smcroute/smcroute.nix
./ollama/ollama.nix
./chromecast/chromecast.nix
./chromecast/chromecast-config.nix
./nw-packet-forwarder/nw-packet-forwarder.nix

];
options.ghaf.reference.services = {
enable = mkEnableOption "Ghaf reference services";
dendrite = mkEnableOption "dendrite-pinecone service";
proxy-business = mkEnableOption "Enable the proxy server service";
google-chromecast = mkEnableOption "Chromecast service";
ollama = mkEnableOption "ollama service";
};
config = mkIf cfg.enable {
ghaf.reference.services = {
dendrite-pinecone.enable = mkForce (cfg.dendrite && isNetVM);
proxy-server.enable = mkForce (cfg.proxy-business && isNetVM);
chromecast.enable = mkForce (cfg.google-chromecast && isNetVM);
};
};
}
76 changes: 9 additions & 67 deletions modules/reference/services/dendrite-pinecone/dendrite-pinecone.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
}:
let
cfg = config.ghaf.reference.services.dendrite-pinecone;
inherit (config.ghaf.reference) services;
dendrite-pineconePkg = pkgs.callPackage ../../../../packages/dendrite-pinecone/default.nix { };
inherit (lib)
mkEnableOption
Expand Down Expand Up @@ -60,99 +61,40 @@ in
}
];

# ip forwarding functionality is needed for iptables
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;

# https://github.com/troglobit/smcroute?tab=readme-ov-file#linux-requirements
boot.kernelPatches = [
{
name = "multicast-routing-config";
patch = null;
extraStructuredConfig = with lib.kernel; {
IP_MULTICAST = yes;
IP_MROUTE = yes;
IP_PIMSM_V1 = yes;
IP_PIMSM_V2 = yes;
IP_MROUTE_MULTIPLE_TABLES = yes; # For multiple routing tables
};
}
];
environment.systemPackages = [ pkgs.smcroute ];
systemd.services."smcroute" = {
description = "Static Multicast Routing daemon";
bindsTo = [ "sys-subsystem-net-devices-${cfg.externalNic}.device" ];
after = [ "sys-subsystem-net-devices-${cfg.externalNic}.device" ];
preStart = ''
configContent=$(cat <<EOF
services.smcroute = {
enable = true;
bindingNic = "${cfg.externalNic}";
rules = ''
mgroup from ${cfg.externalNic} group ${dendrite-pineconePkg.McastUdpIp}
mgroup from ${cfg.internalNic} group ${dendrite-pineconePkg.McastUdpIp}
mroute from ${cfg.externalNic} group ${dendrite-pineconePkg.McastUdpIp} to ${cfg.internalNic}
mroute from ${cfg.internalNic} group ${dendrite-pineconePkg.McastUdpIp} to ${cfg.externalNic}
EOF
)
filePath="/etc/smcroute.conf"
touch $filePath
chmod 200 $filePath
echo "$configContent" > $filePath
chmod 400 $filePath
# wait until ${cfg.externalNic} has an ip
while [ -z "$ip" ]; do
ip=$(${pkgs.nettools}/bin/ifconfig ${cfg.externalNic} | ${pkgs.gawk}/bin/awk '/inet / {print $2}')
[ -z "$ip" ] && ${pkgs.coreutils}/bin/sleep 1
done
exit 0
'';

serviceConfig = {
Type = "simple";
ExecStart = "${pkgs.smcroute}/sbin/smcrouted -n -s -f /etc/smcroute.conf";
#TODO sudo setcap cap_net_admin=ep ${pkgs.smcroute}/sbin/smcroute
# TODO: Add proper AmbientCapabilities= or CapabilityBoundingSet=,
# preferably former and then change user to something else than
# root.
User = "root";
# Automatically restart service when it exits.
Restart = "always";
# Wait a second before restarting.
RestartSec = "5s";
};
wantedBy = [ "multi-user.target" ];
};

networking = {
firewall.enable = true;
firewall.extraCommands = "
# Set the default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow loopback traffic
iptables -A INPUT -i lo -j ACCEPT
# TODO: Move all these TcpPort and things like that, to the options of
# this module, away from from package itself.
# Forward incoming TCP traffic on port ${dendrite-pineconePkg.TcpPort} to internal network(comms-vm)
iptables -t nat -A PREROUTING -i ${cfg.externalNic} -p tcp --dport ${dendrite-pineconePkg.TcpPort} -j DNAT --to-destination ${cfg.serverIpAddr}:${dendrite-pineconePkg.TcpPort}
iptables -t nat -I PREROUTING -i ${cfg.externalNic} -p tcp --dport ${dendrite-pineconePkg.TcpPort} -j DNAT --to-destination ${cfg.serverIpAddr}:${dendrite-pineconePkg.TcpPort}
# Enable NAT for outgoing traffic
iptables -t nat -A POSTROUTING -o ${cfg.externalNic} -p tcp --dport ${dendrite-pineconePkg.TcpPort} -j MASQUERADE
iptables -t nat -I POSTROUTING -o ${cfg.externalNic} -p tcp --dport ${dendrite-pineconePkg.TcpPort} -j MASQUERADE
# Enable NAT for outgoing traffic
iptables -t nat -A POSTROUTING -o ${cfg.externalNic} -p tcp --sport ${dendrite-pineconePkg.TcpPort} -j MASQUERADE
iptables -t nat -I POSTROUTING -o ${cfg.externalNic} -p tcp --sport ${dendrite-pineconePkg.TcpPort} -j MASQUERADE
# Enable NAT for outgoing udp multicast traffic
iptables -t nat -A POSTROUTING -o ${cfg.externalNic} -p udp -d ${dendrite-pineconePkg.McastUdpIp} --dport ${dendrite-pineconePkg.McastUdpPort} -j MASQUERADE
iptables -t nat -I POSTROUTING -o ${cfg.externalNic} -p udp -d ${dendrite-pineconePkg.McastUdpIp} --dport ${dendrite-pineconePkg.McastUdpPort} -j MASQUERADE
# https://github.com/troglobit/smcroute?tab=readme-ov-file#usage
iptables -t mangle -I PREROUTING -i ${cfg.externalNic} -d ${dendrite-pineconePkg.McastUdpIp} -j TTL --ttl-set 1
# ttl value must be set to 1 for avoiding multicast looping
iptables -t mangle -I PREROUTING -i ${cfg.internalNic} -d ${dendrite-pineconePkg.McastUdpIp} -j TTL --ttl-inc 1
# Accept forwarding
iptables -A FORWARD -j ACCEPT
";
};
};
Expand Down
Loading

0 comments on commit 88a2ef8

Please sign in to comment.