mirror of
https://github.com/cjdelisle/cjdns
synced 2025-10-05 16:22:54 +02:00
Allow hard-coding of device public IP in case that it might not be detectable
This commit is contained in:
@@ -432,12 +432,29 @@ static void seeders(List* seeders, struct Allocator* tempAlloc, struct Context*
|
||||
}
|
||||
}
|
||||
|
||||
static void publicPeer(String_t* peerID, Allocator_t* tempAlloc, struct Context* ctx)
|
||||
static void publicPeer(Dict_t* routerConf, Allocator_t* tempAlloc, struct Context* ctx)
|
||||
{
|
||||
String_t* peerID = NULL;
|
||||
String_t* ipv4 = NULL;
|
||||
String_t* ipv6 = NULL;
|
||||
Dict_t* peerInfo = Dict_getDictC(routerConf, "publicPeer");
|
||||
if (peerInfo) {
|
||||
peerID = Dict_getStringC(peerInfo, "id");
|
||||
ipv4 = Dict_getStringC(peerInfo, "ipv4");
|
||||
ipv6 = Dict_getStringC(peerInfo, "ipv6");
|
||||
} else {
|
||||
peerID = Dict_getStringC(routerConf, "publicPeer");
|
||||
}
|
||||
if (!peerID) { return; }
|
||||
Log_debug(ctx->logger, "Setting PeerID [%s]", peerID->bytes);
|
||||
Dict* reqDict = Dict_new(tempAlloc);
|
||||
Dict_putStringC(reqDict, "peerID", peerID, tempAlloc);
|
||||
if (ipv4) {
|
||||
Dict_putStringC(reqDict, "ipv4", ipv4, tempAlloc);
|
||||
}
|
||||
if (ipv6) {
|
||||
Dict_putStringC(reqDict, "ipv6", ipv6, tempAlloc);
|
||||
}
|
||||
rpcCall0(String_CONST("PeeringSeeder_publicPeer"), reqDict, ctx, tempAlloc, NULL, true);
|
||||
}
|
||||
|
||||
@@ -448,7 +465,7 @@ static void routerConfig(Dict* routerConf, struct Allocator* tempAlloc, struct C
|
||||
ipTunnel(Dict_getDictC(routerConf, "ipTunnel"), tempAlloc, ctx);
|
||||
supernodes(Dict_getListC(routerConf, "supernodes"), tempAlloc, ctx);
|
||||
seeders(Dict_getListC(routerConf, "dnsSeeds"), tempAlloc, ctx);
|
||||
publicPeer(Dict_getStringC(routerConf, "publicPeer"), tempAlloc, ctx);
|
||||
publicPeer(routerConf, tempAlloc, ctx);
|
||||
}
|
||||
|
||||
static void ethInterfaceSetBeacon(int ifNum, Dict* eth, struct Context* ctx)
|
||||
|
@@ -262,15 +262,37 @@ static int genconf(struct Allocator* alloc, struct Random* rand, bool eth, bool
|
||||
" \"seed.cjdns.fr\"\n"
|
||||
" ],\n"
|
||||
"\n"
|
||||
" // When publicPeer is set, this node will post its public peering credentials\n"
|
||||
" // When publicPeer id is set, this node will post its public peering credentials\n"
|
||||
" // to its supernode. The specified peerID will be used to identify itself.\n"
|
||||
" // For PKT yielding this must be set to the registered peerID, otherwise\n"
|
||||
" // you can set it to anything. By *convention*, peerIDs that begin with \"PUB_\"\n"
|
||||
" // are shared publicly and those which do not are tested by the snode but not\n"
|
||||
" // shared, allowing you to use the snode's peer tester on an otherwise private\n"
|
||||
" // node.\n"
|
||||
" // node. If you leave \"id\" commented, your peering credentials will remain\n"
|
||||
" // entirely private.\n"
|
||||
" //\n"
|
||||
" // \"publicPeer\": \"PUB_XXX\",\n"
|
||||
" \"publicPeer\": {\n"
|
||||
" // \"id\": \"PUB_XXX\",\n"
|
||||
"\n"
|
||||
" // If you set the public peer, you may also hardcode the IPv4 address.\n"
|
||||
" // By default, cjdns will request its public IP address from its peers, but\n"
|
||||
" // in cases with non-standard routing, you may have a different IP address\n"
|
||||
" // for traffic initiated from outside. In this case, you must manually enter\n"
|
||||
" // the IP address. If the address is entered in the form of \"x.x.x.x\", then\n"
|
||||
" // the IP address will be used, but the port will be detected. If it is entered\n"
|
||||
" // as \"0.0.0.0:xxx\" then the port will be used, but the address will be detected\n"
|
||||
" // finally, if it is in the form of \"x.x.x.x:xxx\" then the address AND port will\n"
|
||||
" // be used.\n"
|
||||
" //\n"
|
||||
" // \"ipv4\": \"1.2.3.4:56789\",\n"
|
||||
"\n"
|
||||
" // If you have a public IPv6 address which cannot be detected, you may hard-code\n"
|
||||
" // it here. The same rules apply as IPv4 addresses: \"xxxx:xxxx::\" means use ip\n"
|
||||
" // but detect port. \"[::]:xxx\" means use port but detect ip, and\n"
|
||||
" // \"[xxxx:xxxx::]:xxx\" means use ip and port from configuration.\n"
|
||||
" //\n"
|
||||
" // \"ipv6\": \"[1234:5678::]:9012\",\n"
|
||||
" },\n"
|
||||
"\n"
|
||||
" // supernodes, if none are specified they'll be taken from your peers\n"
|
||||
" \"supernodes\": [\n"
|
||||
|
@@ -33,7 +33,7 @@ trust-dns-resolver = { workspace = true }
|
||||
ipnetwork = { workspace = true }
|
||||
num_enum = { workspace = true }
|
||||
|
||||
[build_dependencies]
|
||||
[build-dependencies]
|
||||
cc = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
cbindgen = { workspace = true }
|
||||
|
@@ -306,6 +306,8 @@ RTypes_Error_t *Rffi_Seeder_public_peer(Rffi_Seeder *seeder,
|
||||
uint16_t user_num,
|
||||
uint64_t passwd,
|
||||
const String_t *code,
|
||||
const String_t *addr4,
|
||||
const String_t *addr6,
|
||||
Allocator_t *alloc);
|
||||
|
||||
RTypes_Error_t *Rffi_Seeder_public_status(Rffi_Seeder *seeder,
|
||||
|
@@ -1,4 +1,6 @@
|
||||
use anyhow::anyhow;
|
||||
use std::{net::{SocketAddrV4, SocketAddrV6}, str::FromStr};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use cjdns_keys::CJDNSPublicKey;
|
||||
|
||||
use crate::{
|
||||
@@ -127,6 +129,19 @@ pub unsafe extern "C" fn Rffi_Seeder_mk_creds(
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
|
||||
fn parse_addr<T: FromStr>(s: *const String_t) -> Result<Option<T>>
|
||||
where <T as FromStr>::Err: 'static + std::error::Error + Send + Sync,
|
||||
{
|
||||
let code = match cstr(s) {
|
||||
Some(code) => String::from_utf8(code.0)?,
|
||||
None => {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
let out: T = code.parse()?;
|
||||
Ok(Some(out))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn Rffi_Seeder_public_peer(
|
||||
seeder: *mut Rffi_Seeder,
|
||||
@@ -135,6 +150,8 @@ pub unsafe extern "C" fn Rffi_Seeder_public_peer(
|
||||
user_num: u16,
|
||||
passwd: u64,
|
||||
code: *const String_t,
|
||||
addr4: *const String_t,
|
||||
addr6: *const String_t,
|
||||
alloc: *mut Allocator_t,
|
||||
) -> *mut RTypes_Error_t {
|
||||
let s = identity::from_c!(seeder);
|
||||
@@ -142,7 +159,21 @@ pub unsafe extern "C" fn Rffi_Seeder_public_peer(
|
||||
Some(code) => code,
|
||||
None => c_bail!(alloc, anyhow!("code must not be null")),
|
||||
};
|
||||
let (user, pass) = s.seeder.public_peer(user_num, passwd, code.0);
|
||||
let addr4: Option<SocketAddrV4> = match parse_addr(addr4) {
|
||||
Ok(x) => x,
|
||||
Err(e) => c_bail!(alloc, e),
|
||||
};
|
||||
let addr6: Option<SocketAddrV6> = match parse_addr(addr6) {
|
||||
Ok(x) => x,
|
||||
Err(e) => c_bail!(alloc, e),
|
||||
};
|
||||
let (user, pass) = s.seeder.public_peer(
|
||||
user_num,
|
||||
passwd,
|
||||
code.0,
|
||||
addr4,
|
||||
addr6,
|
||||
);
|
||||
*user_out = strc(alloc, user);
|
||||
*pass_out = strc(alloc, pass);
|
||||
std::ptr::null_mut()
|
||||
|
@@ -1,5 +1,6 @@
|
||||
use std::{collections::HashMap, net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, sync::Arc, time::Duration};
|
||||
use anyhow::{anyhow, bail, Result, Context};
|
||||
use boringtun::device::Sock;
|
||||
use cjdns_keys::{CJDNSPublicKey, PublicKey};
|
||||
use parking_lot::Mutex;
|
||||
use tokio::sync::mpsc;
|
||||
@@ -285,11 +286,56 @@ struct MyPeeringPasswd {
|
||||
code: Vec<u8>,
|
||||
}
|
||||
|
||||
macro_rules! split_ip {
|
||||
($ip:expr) => {
|
||||
if let Some(ip) = $ip {
|
||||
(
|
||||
if !ip.ip().is_unspecified() {
|
||||
Some(ip.ip())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
if ip.port() > 0 {
|
||||
Some(ip.port())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MyPeeringInfo {
|
||||
passwd: Option<MyPeeringPasswd>,
|
||||
v4: Option<SocketAddrV4>,
|
||||
v6: Option<SocketAddrV6>,
|
||||
manual_v4: Option<SocketAddrV4>,
|
||||
manual_v6: Option<SocketAddrV6>,
|
||||
}
|
||||
impl MyPeeringInfo {
|
||||
fn get_lladdr4(&self) -> Option<SocketAddrV4> {
|
||||
match (split_ip!(&self.manual_v4), split_ip!(&self.v4)) {
|
||||
((_, None), (_, None)) => None,
|
||||
((None, _), (None, _)) => None,
|
||||
((Some(ip), Some(port)), (_, _)) => Some(SocketAddrV4::new(ip.clone(), port)),
|
||||
((None, Some(port)), (Some(ip), _)) => Some(SocketAddrV4::new(ip.clone(), port)),
|
||||
((Some(ip), None), (_, Some(port))) => Some(SocketAddrV4::new(ip.clone(), port)),
|
||||
((None, None), (Some(ip), Some(port))) => Some(SocketAddrV4::new(ip.clone(), port)),
|
||||
}
|
||||
}
|
||||
fn get_lladdr6(&self) -> Option<SocketAddrV6> {
|
||||
match (split_ip!(&self.manual_v6), split_ip!(&self.v6)) {
|
||||
((_, None), (_, None)) => None,
|
||||
((None, _), (None, _)) => None,
|
||||
((Some(ip), Some(port)), (_, _)) => Some(SocketAddrV6::new(ip.clone(), port, 0, 0)),
|
||||
((None, Some(port)), (Some(ip), _)) => Some(SocketAddrV6::new(ip.clone(), port, 0, 0)),
|
||||
((Some(ip), None), (_, Some(port))) => Some(SocketAddrV6::new(ip.clone(), port, 0, 0)),
|
||||
((None, None), (Some(ip), Some(port))) => Some(SocketAddrV6::new(ip.clone(), port, 0, 0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SeederStatus {
|
||||
@@ -310,7 +356,7 @@ impl Seeder {
|
||||
/// Whether we have an address from got_lladdr
|
||||
pub fn has_lladdr(&self) -> bool {
|
||||
let m = self.mpi.lock();
|
||||
m.v4.is_some() || m.v6.is_some()
|
||||
m.get_lladdr4().is_some() || m.get_lladdr6().is_some()
|
||||
}
|
||||
fn got_lladdr4(&self, lla: &Control_LlAddr_Udp4_t) -> bool {
|
||||
let sa =
|
||||
@@ -392,10 +438,10 @@ impl Seeder {
|
||||
bail!("Missing passwd");
|
||||
};
|
||||
let mut addrs = Vec::new();
|
||||
if let Some(x) = &m.v4 {
|
||||
if let Some(x) = &m.get_lladdr4() {
|
||||
addrs.push(SocketAddr::V4(x.clone()));
|
||||
}
|
||||
if let Some(x) = &m.v6 {
|
||||
if let Some(x) = &m.get_lladdr6() {
|
||||
addrs.push(SocketAddr::V6(x.clone()));
|
||||
}
|
||||
if addrs.is_empty() {
|
||||
@@ -421,9 +467,13 @@ impl Seeder {
|
||||
user_num: u16,
|
||||
passwd: u64,
|
||||
code: Vec<u8>,
|
||||
sa4: Option<SocketAddrV4>,
|
||||
sa6: Option<SocketAddrV6>,
|
||||
) -> (String, String) {
|
||||
let mut m = self.mpi.lock();
|
||||
m.passwd = Some(MyPeeringPasswd { user_num, passwd, code });
|
||||
m.manual_v4 = sa4;
|
||||
m.manual_v6 = sa6;
|
||||
let p = cjdns_bytes::dnsseed::CjdnsPeer {
|
||||
address: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(1,1,1,1)), 1),
|
||||
pubkey: [0_u8; 32],
|
||||
@@ -450,8 +500,8 @@ impl Seeder {
|
||||
|
||||
pub fn get_status(&self) -> SeederStatus {
|
||||
let m = self.mpi.lock();
|
||||
let v4 = m.v4.map(|x|x.to_string());
|
||||
let v6 = m.v6.map(|x|x.to_string());
|
||||
let v4 = m.get_lladdr4().map(|x|x.to_string());
|
||||
let v6 = m.get_lladdr6().map(|x|x.to_string());
|
||||
let peer_id = m.passwd.as_ref().map(|p|p.code.clone());
|
||||
drop(m);
|
||||
let peer_id = if let Some(peer_id) = peer_id {
|
||||
|
@@ -227,7 +227,12 @@ Err_DEFUN PeeringSeeder_publicStatus(PeeringSeeder_PublicStatus_t** outP, Peerin
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Err_DEFUN PeeringSeeder_publicPeer(PeeringSeeder_t* self, String_t* code, Allocator_t* reqAlloc)
|
||||
Err_DEFUN PeeringSeeder_publicPeer(
|
||||
PeeringSeeder_t* self,
|
||||
String_t* code,
|
||||
String_t* addr4,
|
||||
String_t* addr6,
|
||||
Allocator_t* reqAlloc)
|
||||
{
|
||||
PeeringSeeder_pvt_t* pq = Identity_check((PeeringSeeder_pvt_t*) self);
|
||||
if (code == NULL) {
|
||||
@@ -250,6 +255,8 @@ Err_DEFUN PeeringSeeder_publicPeer(PeeringSeeder_t* self, String_t* code, Alloca
|
||||
pq->userNum,
|
||||
pq->pass,
|
||||
code,
|
||||
addr4,
|
||||
addr6,
|
||||
reqAlloc));
|
||||
|
||||
Assert_true(user->len < sizeof pq->login);
|
||||
|
@@ -45,7 +45,12 @@ void PeeringSeeder_setSnode(PeeringSeeder_t* self, struct Address* snode);
|
||||
|
||||
#define PeeringSeeder_publicPeer_ID_MAX_LEN 30
|
||||
|
||||
Err_DEFUN PeeringSeeder_publicPeer(PeeringSeeder_t* self, String* code, Allocator_t* reqAlloc);
|
||||
Err_DEFUN PeeringSeeder_publicPeer(
|
||||
PeeringSeeder_t* self,
|
||||
String_t* code,
|
||||
String_t* addr4,
|
||||
String_t* addr6,
|
||||
Allocator_t* reqAlloc);
|
||||
|
||||
// Get as a void pointer so that we don't need to pull in Rffi
|
||||
void* PeeringSeeder_getRsSeeder(PeeringSeeder_t* self);
|
||||
|
@@ -108,9 +108,11 @@ static void publicPeer(Dict* args, void* vcontext, String* txid, struct Allocato
|
||||
{
|
||||
struct Context* ctx = Identity_check((struct Context*) vcontext);
|
||||
String* peerCode = Dict_getStringC(args, "peerID");
|
||||
String* ipv4 = Dict_getStringC(args, "ipv4");
|
||||
String* ipv6 = Dict_getStringC(args, "ipv6");
|
||||
char* err = "none";
|
||||
RTypes_Error_t* er =
|
||||
PeeringSeeder_publicPeer(ctx->sp, peerCode, requestAlloc);
|
||||
PeeringSeeder_publicPeer(ctx->sp, peerCode, ipv4, ipv6, requestAlloc);
|
||||
if (er) {
|
||||
err = Rffi_printError(er, requestAlloc);
|
||||
}
|
||||
@@ -171,7 +173,9 @@ void PeeringSeeder_admin_register(PeeringSeeder_t* sp,
|
||||
|
||||
Admin_registerFunction("PeeringSeeder_publicPeer", publicPeer, ctx, true,
|
||||
((struct Admin_FunctionArg[]) {
|
||||
{ .name = "peerID", .required = false, .type = "String" }
|
||||
{ .name = "peerID", .required = false, .type = "String" },
|
||||
{ .name = "ipv4", .required = false, .type = "String" },
|
||||
{ .name = "ipv6", .required = false, .type = "String" }
|
||||
}), admin);
|
||||
|
||||
Admin_registerFunctionNoArgs("PeeringSeeder_publicStatus", publicStatus, ctx, true, admin);
|
||||
|
Reference in New Issue
Block a user