pub struct ExitPolicyRule {
pub is_accept: bool,
pub min_port: u16,
pub max_port: u16,
/* private fields */
}Expand description
A single rule in an exit policy.
Each rule specifies whether to accept or reject traffic to a particular address and port combination. Rules are evaluated in order, and the first matching rule determines whether traffic is allowed.
§Rule Format
Rules follow the Tor exit policy format:
accept|reject[6] addrspec:portspec§Matching Semantics
A rule matches a destination if:
- The destination address matches the rule’s address specification (considering CIDR masks and address family)
- The destination port is within the rule’s port range
§Address Family Matching
- Wildcard (
*) rules match both IPv4 and IPv6 addresses - IPv4-specific rules (
*4, explicit IPv4) only match IPv4 addresses - IPv6-specific rules (
*6, explicit IPv6,accept6/reject6) only match IPv6
§Example
use stem_rs::exit_policy::ExitPolicyRule;
use std::net::IpAddr;
// Parse a rule that accepts HTTP traffic
let rule = ExitPolicyRule::parse("accept *:80").unwrap();
assert!(rule.is_accept);
assert!(rule.is_address_wildcard());
assert!(!rule.is_port_wildcard());
// Check if the rule matches a destination
let addr: IpAddr = "192.168.1.1".parse().unwrap();
assert!(rule.is_match(Some(addr), Some(80)));
assert!(!rule.is_match(Some(addr), Some(443)));
// Parse a CIDR rule
let rule = ExitPolicyRule::parse("reject 10.0.0.0/8:*").unwrap();
assert!(!rule.is_accept);
assert_eq!(rule.get_masked_bits(), Some(8));§See Also
ExitPolicy: A collection of rules forming a complete policyMicroExitPolicy: A compact port-only policy format
Fields§
§is_accept: boolWhether this rule accepts (true) or rejects (false) matching traffic.
min_port: u16The minimum port number this rule applies to (inclusive).
max_port: u16The maximum port number this rule applies to (inclusive).
Implementations§
Source§impl ExitPolicyRule
impl ExitPolicyRule
Sourcepub fn parse(rule: &str) -> Result<Self, Error>
pub fn parse(rule: &str) -> Result<Self, Error>
Parses an exit policy rule from a string.
The rule must follow the Tor exit policy format:
accept|reject[6] addrspec:portspec§Arguments
rule- The rule string to parse
§Supported Formats
§Actions
accept- Allow matching trafficreject- Block matching trafficaccept6- Allow matching IPv6 traffic onlyreject6- Block matching IPv6 traffic only
§Address Specifications
*- Any address (IPv4 or IPv6)*4- Any IPv4 address*6- Any IPv6 addressA.B.C.D- Specific IPv4 addressA.B.C.D/N- IPv4 CIDR notation (N = 0-32)A.B.C.D/M.M.M.M- IPv4 with subnet mask[IPv6]- Specific IPv6 address[IPv6]/N- IPv6 CIDR notation (N = 0-128)
§Port Specifications
*- Any port (1-65535)N- Single portN-M- Port range (inclusive)
§Errors
Returns Error::Parse if:
- The rule doesn’t start with
acceptorreject - The address specification is invalid
- The port specification is invalid
- The CIDR mask is out of range
- The port range is invalid (min > max)
§Example
use stem_rs::exit_policy::ExitPolicyRule;
// Various valid rule formats
let rule = ExitPolicyRule::parse("accept *:80").unwrap();
let rule = ExitPolicyRule::parse("reject 10.0.0.0/8:*").unwrap();
let rule = ExitPolicyRule::parse("accept 192.168.0.0/255.255.0.0:80-443").unwrap();
let rule = ExitPolicyRule::parse("accept6 [::1]:22").unwrap();
let rule = ExitPolicyRule::parse("reject [2001:db8::]/32:*").unwrap();
// Invalid rules
assert!(ExitPolicyRule::parse("allow *:80").is_err()); // Invalid action
assert!(ExitPolicyRule::parse("accept *").is_err()); // Missing port
assert!(ExitPolicyRule::parse("accept *:443-80").is_err()); // Invalid rangeSourcepub fn is_match(&self, address: Option<IpAddr>, port: Option<u16>) -> bool
pub fn is_match(&self, address: Option<IpAddr>, port: Option<u16>) -> bool
Checks if this rule matches a given destination.
A rule matches if both the address and port match the rule’s specifications.
If either the address or port is None, the rule performs a “fuzzy” match
where the missing component is considered to potentially match.
This is equivalent to calling is_match_strict
with strict = false.
§Arguments
address- The destination IP address, orNoneto match any addressport- The destination port, orNoneto match any port
§Returns
true if the rule matches the destination, false otherwise.
§Matching Rules
- If the rule has a wildcard address, any address matches
- If the rule has a specific address/CIDR, only addresses in that range match
- IPv4 rules don’t match IPv6 addresses and vice versa
- If the rule has a wildcard port, any port matches
- If the rule has a specific port range, only ports in that range match
§Example
use stem_rs::exit_policy::ExitPolicyRule;
use std::net::IpAddr;
let rule = ExitPolicyRule::parse("accept 10.0.0.0/8:80-443").unwrap();
// Exact match
let addr: IpAddr = "10.1.2.3".parse().unwrap();
assert!(rule.is_match(Some(addr), Some(80)));
assert!(rule.is_match(Some(addr), Some(443)));
assert!(!rule.is_match(Some(addr), Some(22)));
// Address outside CIDR range
let addr: IpAddr = "192.168.1.1".parse().unwrap();
assert!(!rule.is_match(Some(addr), Some(80)));
// Fuzzy match (None means "any")
assert!(rule.is_match(None, Some(80))); // Any address, port 80Sourcepub fn is_match_strict(
&self,
address: Option<IpAddr>,
port: Option<u16>,
strict: bool,
) -> bool
pub fn is_match_strict( &self, address: Option<IpAddr>, port: Option<u16>, strict: bool, ) -> bool
Checks if this rule matches a destination with strict mode option.
Similar to is_match, but with control over how
fuzzy matches (when address or port is None) are handled.
§Arguments
address- The destination IP address, orNoneto match any addressport- The destination port, orNoneto match any portstrict- Controls fuzzy match behavior:false: Fuzzy matches returntruefor accept rules,falsefor rejecttrue: Fuzzy matches returnfalsefor accept rules,truefor reject
§Strict Mode Semantics
When strict = true, the question becomes “does this rule match ALL
possible values for the missing component?” rather than “does this rule
match ANY possible value?”
This is useful for determining if traffic can definitely exit (strict=true) versus if traffic might be able to exit (strict=false).
§Example
use stem_rs::exit_policy::ExitPolicyRule;
let accept_rule = ExitPolicyRule::parse("accept 10.0.0.0/8:80").unwrap();
// Non-strict: "can ANY address on port 80 match?"
assert!(accept_rule.is_match_strict(None, Some(80), false));
// Strict: "do ALL addresses on port 80 match?"
assert!(!accept_rule.is_match_strict(None, Some(80), true));Sourcepub fn is_address_wildcard(&self) -> bool
pub fn is_address_wildcard(&self) -> bool
Checks if this rule matches any address (is an address wildcard).
A rule is an address wildcard if its address specification is *,
which matches both IPv4 and IPv6 addresses.
Note that *4 and *6 are NOT considered wildcards by this method,
as they only match one address family.
§Returns
true if the rule matches any address, false otherwise.
§Example
use stem_rs::exit_policy::ExitPolicyRule;
assert!(ExitPolicyRule::parse("accept *:80").unwrap().is_address_wildcard());
assert!(!ExitPolicyRule::parse("accept *4:80").unwrap().is_address_wildcard());
assert!(!ExitPolicyRule::parse("accept *6:80").unwrap().is_address_wildcard());
assert!(!ExitPolicyRule::parse("accept 10.0.0.0/8:80").unwrap().is_address_wildcard());Sourcepub fn is_port_wildcard(&self) -> bool
pub fn is_port_wildcard(&self) -> bool
Checks if this rule matches any port (is a port wildcard).
A rule is a port wildcard if its port specification covers all valid
ports (1-65535), typically written as * in the rule string.
§Returns
true if the rule matches any port, false otherwise.
§Example
use stem_rs::exit_policy::ExitPolicyRule;
assert!(ExitPolicyRule::parse("accept *:*").unwrap().is_port_wildcard());
assert!(ExitPolicyRule::parse("accept *:1-65535").unwrap().is_port_wildcard());
assert!(!ExitPolicyRule::parse("accept *:80").unwrap().is_port_wildcard());
assert!(!ExitPolicyRule::parse("accept *:80-443").unwrap().is_port_wildcard());Sourcepub fn get_address_type(&self) -> AddressType
pub fn get_address_type(&self) -> AddressType
Returns the address type of this rule.
§Returns
The AddressType indicating whether this rule matches:
AddressType::Wildcard: Any address (IPv4 or IPv6)AddressType::IPv4: Only IPv4 addressesAddressType::IPv6: Only IPv6 addresses
§Example
use stem_rs::exit_policy::{ExitPolicyRule, AddressType};
let rule = ExitPolicyRule::parse("accept *:80").unwrap();
assert_eq!(rule.get_address_type(), AddressType::Wildcard);
let rule = ExitPolicyRule::parse("accept 192.168.1.1:80").unwrap();
assert_eq!(rule.get_address_type(), AddressType::IPv4);
let rule = ExitPolicyRule::parse("accept [::1]:80").unwrap();
assert_eq!(rule.get_address_type(), AddressType::IPv6);Sourcepub fn get_mask(&self) -> Option<IpAddr>
pub fn get_mask(&self) -> Option<IpAddr>
Returns the subnet mask as an IP address.
For IPv4 rules, returns the mask in dotted-quad notation (e.g., 255.255.0.0).
For IPv6 rules, returns the mask as an IPv6 address.
For wildcard rules, returns None.
§Returns
The subnet mask as an IpAddr, or None for wildcard rules.
§Example
use stem_rs::exit_policy::ExitPolicyRule;
use std::net::IpAddr;
let rule = ExitPolicyRule::parse("accept 192.168.0.0/16:*").unwrap();
assert_eq!(rule.get_mask(), Some("255.255.0.0".parse::<IpAddr>().unwrap()));
let rule = ExitPolicyRule::parse("accept 10.0.0.0/8:*").unwrap();
assert_eq!(rule.get_mask(), Some("255.0.0.0".parse::<IpAddr>().unwrap()));
let rule = ExitPolicyRule::parse("accept *:80").unwrap();
assert_eq!(rule.get_mask(), None);Sourcepub fn get_masked_bits(&self) -> Option<u8>
pub fn get_masked_bits(&self) -> Option<u8>
Returns the number of bits in the subnet mask.
For CIDR notation like 10.0.0.0/8, this returns 8.
For specific addresses without a mask, returns the full mask (32 for IPv4, 128 for IPv6).
For wildcard rules, returns None.
§Returns
The number of mask bits, or None for wildcard rules.
§Example
use stem_rs::exit_policy::ExitPolicyRule;
let rule = ExitPolicyRule::parse("accept 10.0.0.0/8:*").unwrap();
assert_eq!(rule.get_masked_bits(), Some(8));
let rule = ExitPolicyRule::parse("accept 192.168.1.1:80").unwrap();
assert_eq!(rule.get_masked_bits(), Some(32)); // Full mask for specific address
let rule = ExitPolicyRule::parse("accept *:80").unwrap();
assert_eq!(rule.get_masked_bits(), None);Sourcepub fn is_default(&self) -> bool
pub fn is_default(&self) -> bool
Checks if this rule is part of Tor’s default exit policy suffix.
Tor appends a default policy suffix that blocks commonly abused ports
(SMTP, NetBIOS, etc.) and then accepts all other traffic. This method
returns true if this rule was identified as part of that suffix.
§Returns
true if this rule is part of the default policy suffix, false otherwise.
§See Also
ExitPolicy::has_default: Check if a policy contains default rulesExitPolicy::strip_default: Remove default rules from a policy
Sourcepub fn is_private(&self) -> bool
pub fn is_private(&self) -> bool
Checks if this rule was expanded from the private keyword.
The private keyword in Tor exit policies expands to rules blocking
traffic to private/internal IP ranges (10.0.0.0/8, 192.168.0.0/16,
127.0.0.0/8, etc.). This method returns true if this rule was
identified as part of that expansion.
§Returns
true if this rule was expanded from private, false otherwise.
§See Also
ExitPolicy::has_private: Check if a policy contains private rulesExitPolicy::strip_private: Remove private rules from a policy
Sourcepub fn address(&self) -> Option<IpAddr>
pub fn address(&self) -> Option<IpAddr>
Returns the IP address this rule applies to.
For rules with a specific address or CIDR range, returns the base address.
For wildcard rules, returns None.
§Returns
The IP address, or None for wildcard rules.
§Example
use stem_rs::exit_policy::ExitPolicyRule;
use std::net::IpAddr;
let rule = ExitPolicyRule::parse("accept 192.168.1.1:80").unwrap();
assert_eq!(rule.address(), Some("192.168.1.1".parse::<IpAddr>().unwrap()));
let rule = ExitPolicyRule::parse("accept 10.0.0.0/8:*").unwrap();
assert_eq!(rule.address(), Some("10.0.0.0".parse::<IpAddr>().unwrap()));
let rule = ExitPolicyRule::parse("accept *:80").unwrap();
assert_eq!(rule.address(), None);Trait Implementations§
Source§impl Clone for ExitPolicyRule
impl Clone for ExitPolicyRule
Source§fn clone(&self) -> ExitPolicyRule
fn clone(&self) -> ExitPolicyRule
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more