diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..11d7baa --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +target +*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..8675aaf --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,21 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "neco" +version = "0.1.0" +dependencies = [ + "safe_libc", +] + +[[package]] +name = "safe_libc" +version = "0.1.0" +dependencies = [ + "libc", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..b83531d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "neco" +version = "0.1.0" +authors = ["Matthias Schiffer "] +edition = "2018" + +[dependencies] +safe_libc = { path = "safe_libc" } + +[profile.dev] +lto = true +panic = "abort" + +[profile.release] +lto = true +panic = "abort" diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 4bad81e..0000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2012-2019, Matthias Schiffer -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 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. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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. diff --git a/meson.build b/meson.build deleted file mode 100644 index 0cbd657..0000000 --- a/meson.build +++ /dev/null @@ -1,9 +0,0 @@ -project('neco', 'c', default_options : ['c_std=gnu11']) - -cc = meson.get_compiler('c') -libubox_dep = cc.find_library('ubox') - -libjson_c_dep = dependency('json-c', method : 'pkg-config') -libmnl_dep = dependency('libmnl', method : 'pkg-config') - -subdir('src') diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..218e203 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +hard_tabs = true diff --git a/safe_libc/Cargo.toml b/safe_libc/Cargo.toml new file mode 100644 index 0000000..34f8f79 --- /dev/null +++ b/safe_libc/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "safe_libc" +version = "0.1.0" +authors = ["Matthias Schiffer "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libc = { version = "0.2.71", default-features = false } diff --git a/safe_libc/src/boxed.rs b/safe_libc/src/boxed.rs new file mode 100644 index 0000000..a0bbfb4 --- /dev/null +++ b/safe_libc/src/boxed.rs @@ -0,0 +1,78 @@ +use core::{marker, mem, ptr}; +use core::ops::{Deref, DerefMut}; + +pub trait Dealloc { + unsafe fn dealloc(p: *mut T); +} + +#[repr(transparent)] +pub struct BoxLike> { + inner: ptr::NonNull, + _phantom: marker::PhantomData, + _dropper: marker::PhantomData, +} + +impl> BoxLike { + #[inline] + pub unsafe fn from_raw_unchecked(p: *mut T) -> Self { + BoxLike { + inner: ptr::NonNull::new_unchecked(p), + _phantom: marker::PhantomData, + _dropper: marker::PhantomData, + } + } + + #[inline] + pub unsafe fn from_raw(p: *mut T) -> Option { + if p.is_null() { + None + } else { + Some(Self::from_raw_unchecked(p)) + } + } + + #[inline] + pub fn into_raw(self) -> *mut T { + let p = self.inner.as_ptr(); + mem::forget(self); + p + } +} + +impl> Drop for BoxLike { + #[inline] + fn drop(&mut self) { + let p = self.inner.as_ptr(); + unsafe { + ptr::drop_in_place(p); + D::dealloc(p); + } + } +} + +impl> Deref for BoxLike { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + unsafe { self.inner.as_ref() } + } +} + +impl> DerefMut for BoxLike { + #[inline] + fn deref_mut(&mut self) -> &mut T { + unsafe { self.inner.as_mut() } + } +} + +pub struct DeallocFree; + +impl Dealloc for DeallocFree { + #[inline] + unsafe fn dealloc(p: *mut T) { + libc::free(p as _); + } +} + +pub type CBox = BoxLike; diff --git a/safe_libc/src/errno.rs b/safe_libc/src/errno.rs new file mode 100644 index 0000000..fdb1246 --- /dev/null +++ b/safe_libc/src/errno.rs @@ -0,0 +1,34 @@ +use crate::string; + +use core::fmt; + +#[derive(Clone, Copy, Debug)] +#[repr(transparent)] +pub struct Errno(pub libc::c_int); + +extern "C" { + #[ffi_const] + pub fn __errno_location() -> *mut libc::c_int; +} + +#[inline] +pub fn errno() -> Errno { + unsafe { Errno(*__errno_location()) } +} + +impl fmt::Display for Errno { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut buf = [0u8; 1024]; + let cstr = unsafe { + if libc::strerror_r(self.0, buf.as_mut_ptr().cast(), buf.len()) != 0 { + return Err(fmt::Error); + } + string::CStr::from_bytes_with_nul_unchecked(&buf) + }; + match cstr.to_str() { + Err(_) => Err(fmt::Error), + Ok(s) => f.write_str(s), + } + } +} diff --git a/safe_libc/src/lib.rs b/safe_libc/src/lib.rs new file mode 100644 index 0000000..cbc4071 --- /dev/null +++ b/safe_libc/src/lib.rs @@ -0,0 +1,21 @@ +#![no_std] +#![feature(extern_types)] +#![feature(slice_ptr_len)] +#![feature(ffi_const)] + +extern crate alloc; + +pub use libc::*; + +mod util; + +pub mod boxed; +pub mod errno; +pub mod stdio; +pub mod string; + +extern "C" { + // pub static stdin: *mut libc::FILE; + pub static stdout: *mut libc::FILE; + pub static stderr: *mut libc::FILE; +} diff --git a/safe_libc/src/stdio.rs b/safe_libc/src/stdio.rs new file mode 100644 index 0000000..2942405 --- /dev/null +++ b/safe_libc/src/stdio.rs @@ -0,0 +1,104 @@ +use crate::{self as libc, errno, string}; + +use core::fmt; +use core::ops::{Deref, DerefMut}; + +pub struct Error { + pub errno: errno::Errno, +} + +impl From for fmt::Error { + fn from(_err: Error) -> fmt::Error { + fmt::Error + } +} + +pub type Result = core::result::Result; + +#[inline] +fn check_io(ok: bool) -> Result<()> { + if ok { + Ok(()) + } else { + Err(Error { + errno: errno::errno(), + }) + } +} + +pub struct BasicOStream(*mut libc::FILE); + +unsafe impl Sync for BasicOStream {} +unsafe impl Send for BasicOStream {} + +pub type Stdout = BasicOStream; +pub type Stderr = BasicOStream; + +#[inline] +pub fn stdout() -> Stdout { + BasicOStream(unsafe { libc::stdout }) +} + +#[inline] +pub fn stderr() -> Stderr { + BasicOStream(unsafe { libc::stderr }) +} + +impl BasicOStream { + #[inline] + pub fn flush(&mut self) -> Result<()> { + check_io(unsafe { libc::fflush(self.0) } == 0) + } + + #[inline] + pub fn write(&mut self, b: &[u8]) -> Result<()> { + check_io(unsafe { libc::fwrite(b.as_ptr().cast(), 1, b.len(), self.0) } == b.len()) + } + + #[inline] + pub fn puts(&mut self, s: &string::CStr) -> Result<()> { + check_io(unsafe { libc::fputs(s.as_ptr(), self.0) } != libc::EOF) + } +} + +impl fmt::Write for BasicOStream { + #[inline] + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write(s.as_bytes())?; + Ok(()) + } +} + +pub struct OStream(BasicOStream); + +impl OStream { + #[inline] + pub unsafe fn from_raw(file: *mut libc::FILE) -> OStream { + OStream(BasicOStream(file)) + } +} + +impl Drop for OStream { + #[inline] + fn drop(&mut self) { + unsafe { + libc::fclose((self.0).0); + } + } +} + +impl Deref for OStream { + type Target = BasicOStream; + + #[inline] + fn deref(&self) -> &BasicOStream { + &self.0 + } +} + +impl DerefMut for OStream { + #[inline] + fn deref_mut(&mut self) -> &mut BasicOStream { + &mut self.0 + } +} diff --git a/safe_libc/src/string.rs b/safe_libc/src/string.rs new file mode 100644 index 0000000..5483e08 --- /dev/null +++ b/safe_libc/src/string.rs @@ -0,0 +1,142 @@ +use crate::{self as libc, boxed::CBox, util}; + +use core::{mem, slice}; +use core::ops::{Deref, DerefMut}; + +//pub struct FromBytesWithNulError {} + +extern "C" { + type RawCStr; +} + +#[repr(transparent)] +pub struct CStr(RawCStr); + +impl CStr { + #[inline] + pub unsafe fn from_ptr<'a>(p: *const libc::c_char) -> &'a CStr { + &*(p as *const CStr) + } + + #[inline] + pub unsafe fn from_mut_ptr<'a>(p: *mut libc::c_char) -> &'a mut CStr { + &mut *(p as *mut CStr) + } + + #[inline] + pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + CStr::from_ptr(bytes.as_ptr().cast()) + } + + // TODO + //pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { + //} + + #[inline] + pub fn len(&self) -> usize { + unsafe { libc::strlen(self.as_ptr()) } + } + + #[inline] + pub const fn as_ptr(&self) -> *const libc::c_char { + (self as *const CStr).cast() + } + + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut libc::c_char { + (self as *mut CStr).cast() + } + + #[inline] + pub fn to_bytes(&self) -> &[u8] { + unsafe { slice::from_raw_parts(self.as_ptr().cast(), self.len()) } + } + + #[inline] + pub fn to_mut_bytes(&mut self) -> &mut [u8] { + unsafe { slice::from_raw_parts_mut(self.as_mut_ptr().cast(), self.len()) } + } + + #[inline] + pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> { + core::str::from_utf8(self.to_bytes()) + } + + #[inline] + pub fn to_mut_str(&mut self) -> Result<&mut str, core::str::Utf8Error> { + core::str::from_utf8_mut(self.to_mut_bytes()) + } + + #[inline] + pub fn to_owned(self: &CStr) -> CString { + CString::from(self) + } +} + +#[macro_export] +macro_rules! cstr { + ($s:expr) => { + unsafe { $crate::string::CStr::from_bytes_with_nul_unchecked(concat!($s, "\0").as_bytes()) } + }; +} + +pub struct CString { + inner: CBox, +} + +impl CString { + #[inline] + pub unsafe fn from_raw(p: *mut libc::c_char) -> CString { + CString { + inner: CBox::from_raw_unchecked(p as *mut CStr) + } + } + + #[inline] + pub fn into_raw(mut self) -> *mut libc::c_char { + let p = self.as_mut_ptr(); + mem::forget(self); + p + } +} + +impl Deref for CString { + type Target = CStr; + + #[inline] + fn deref(&self) -> &CStr { + &*self.inner + } +} + +impl DerefMut for CString { + #[inline] + fn deref_mut(&mut self) -> &mut CStr { + &mut *self.inner + } +} + +impl From<&[u8]> for CString { + fn from(s: &[u8]) -> CString { + unsafe { + CString::from_raw(util::must_succeed(libc::strndup( + s.as_ptr().cast(), + s.len(), + ))) + } + } +} + +impl From<&str> for CString { + #[inline] + fn from(s: &str) -> CString { + CString::from(s.as_bytes()) + } +} + +impl From<&CStr> for CString { + #[inline] + fn from(s: &CStr) -> CString { + unsafe { CString::from_raw(util::must_succeed(libc::strdup(s.as_ptr()))) } + } +} diff --git a/safe_libc/src/util.rs b/safe_libc/src/util.rs new file mode 100644 index 0000000..d37954c --- /dev/null +++ b/safe_libc/src/util.rs @@ -0,0 +1,9 @@ +use alloc::alloc; + +#[inline] +pub fn must_succeed(p: *mut T) -> *mut T { + if p.is_null() { + alloc::handle_alloc_error(alloc::Layout::new::()) + } + p +} diff --git a/src/config-load.c b/src/config-load.c deleted file mode 100644 index 19b9d3a..0000000 --- a/src/config-load.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "config-load.h" -#include "config-process.h" -#include "device.h" -#include "util.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -bool read_config(const char *path) { - struct json_object *config = json_object_from_file(path); - if (!config) - return false; - - struct avl_tree *devices = config_process(config); - json_object_put(config); - - if (!devices) - return false; - - device_t *dev, *tmp; - avl_for_each_element(devices, dev, node) - dev->type->init(dev); - - //avl_for_each_element(devices, dev, node) - // dev->type->release(dev); - - avl_remove_all_elements(devices, dev, node, tmp) - dev->type->free(dev); - - free(devices); - - return true; -} diff --git a/src/config-load.h b/src/config-load.h deleted file mode 100644 index e2b4736..0000000 --- a/src/config-load.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include - -bool read_config(const char *path); diff --git a/src/config-process.c b/src/config-process.c deleted file mode 100644 index c1634d5..0000000 --- a/src/config-process.c +++ /dev/null @@ -1,58 +0,0 @@ -#include "config-process.h" -#include "device.h" -#include "util.h" - -#include - -#include -#include -#include - - -typedef struct _process_ctx { - struct avl_tree *ret; -} process_ctx_t; - -typedef struct _config_subtype { - struct avl_node node; -} config_subtype_t; - - -static device_t * config_process_device(const char *name, struct json_object *obj) { - const char *typename = NULL; - struct json_object *device = neco_json_get_value(obj, "device", json_type_object); - if (device) - typename = neco_json_get_string(device, "type"); - - const device_type_t *type = get_device_type(typename ?: "interface"); - if (!type) - return NULL; - - return type->process_config(name, obj); -} - -struct avl_tree * config_process(struct json_object *config) { - if (!json_object_is_type(config, json_type_object)) - return NULL; - - struct json_object *devices = neco_json_get_value(config, "devices", json_type_object); - if (!devices) - return NULL; - - process_ctx_t ctx; - ctx.ret = calloc(1, sizeof(*ctx.ret)); - if (!ctx.ret) - return NULL; - - avl_init(ctx.ret, avl_strcmp, false, NULL); - - json_object_object_foreach(devices, name, obj) { - device_t *device = config_process_device(name, obj); - if (!device) - continue; - - avl_insert(ctx.ret, &device->node); - } - - return ctx.ret; -} diff --git a/src/config-process.h b/src/config-process.h deleted file mode 100644 index 3903d78..0000000 --- a/src/config-process.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include -#include - -struct avl_tree * config_process(struct json_object *config); diff --git a/src/device-bridge.c b/src/device-bridge.c deleted file mode 100644 index 11b24b0..0000000 --- a/src/device-bridge.c +++ /dev/null @@ -1,131 +0,0 @@ -#include "device-common.h" -#include "netlink.h" -#include "util.h" - -#include - -#include - -#include -#include -#include - -static device_type_t device_type_bridge; - -typedef struct _device_bridge { - device_t device; - device_common_t common; -} device_bridge_t; - -static void bridge_free(device_t *dev) { - device_bridge_t *iface = container_of(dev, device_bridge_t, device); - - VECTOR_FREE(iface->common.addrs); - free(NODE_NAME(dev)); - free(iface); -} - -static device_t * bridge_process_config(const char *name, struct json_object *config) { - device_bridge_t *iface = calloc(1, sizeof(*iface)); - if (!iface) - return NULL; - - device_t *dev = &iface->device; - dev->type = &device_type_bridge; - - NODE_NAME(dev) = strdup(name); - if (!NODE_NAME(dev)) { - free(iface); - return NULL; - } - - if (!device_common_process_config(&iface->common, config)) - goto err; - - return dev; - -err: - bridge_free(dev); - return NULL; -} - -static bool bridge_nl_create(device_bridge_t *bridge) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - - struct mnl_socket *nl = nl_socket(); - - struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = RTM_NEWLINK; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE; - int seq = nlh->nlmsg_seq = nl_seq(); - - struct ifinfomsg *ifi = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifi)); - ifi->ifi_family = AF_UNSPEC; - - mnl_attr_put_str(nlh, IFLA_IFNAME, NODE_NAME(&bridge->device)); - - struct nlattr *linkinfo = mnl_attr_nest_start(nlh, IFLA_LINKINFO); - mnl_attr_put_str(nlh, IFLA_INFO_KIND, "bridge"); - mnl_attr_nest_end(nlh, linkinfo); - - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { - perror("mnl_socket_sendto"); - return false; - } - - int ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) { - perror("mnl_socket_recvfrom"); - return false; - } - - ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL); - if (ret == -1) { - perror("mnl_cb_run"); - return false; - } - - return true; -} - -static void bridge_init(device_t *dev) { - device_bridge_t *bridge = container_of(dev, device_bridge_t, device); - - if (!bridge_nl_create(bridge)) - return; - - unsigned ifindex = if_nametoindex(NODE_NAME(dev)); - if (!ifindex) - return; - - device_common_init(&bridge->common, ifindex); -} - -static void bridge_update(device_t *dev) { -} - -static void bridge_release(device_t *dev) { - /* - device_bridge_t *bridge = container_of(dev, device_bridge_t, device); - - unsigned ifindex = if_nametoindex(NODE_NAME(dev)); - if (!ifindex) - return; - - device_common_release(&bridge->common, ifindex); - */ -} - -static device_type_t device_type_bridge = { - .process_config = bridge_process_config, - .free = bridge_free, - - .init = bridge_init, - .update = bridge_update, - .release = bridge_release, -}; - -__attribute__((constructor)) -static void bridge_constructor(void) { - register_device_type("bridge", &device_type_bridge); -} diff --git a/src/device-common.c b/src/device-common.c deleted file mode 100644 index 1dc4490..0000000 --- a/src/device-common.c +++ /dev/null @@ -1,299 +0,0 @@ -#include "device-common.h" -#include "netlink.h" -#include "util.h" - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -static unsigned long strtoul_safe(const char *str) { - char *endptr; - - errno = 0; - unsigned long val = strtoul(str, &endptr, 10); - if (endptr == str || *endptr) - errno = EINVAL; - - return val; -} - -static bool parse_address(ipaddr_t *addr, const char *str) { - if (inet_pton(AF_INET, str, &addr->addr4)) { - addr->af = AF_INET; - return true; - } - - if (inet_pton(AF_INET6, str, &addr->addr6)) { - addr->af = AF_INET6; - return true; - } - - return false; -} - -static bool parse_prefix(ipaddr_prefix_t *prefix, const char *str, bool allow_host) { - const char *slash = strrchr(str, '/'); - if (!slash) - return false; - - size_t len = slash - str; - char buf[len+1]; - memcpy(buf, str, len); - buf[len] = 0; - - if (!parse_address(&prefix->addr, buf)) - return false; - - long plen = strtoul_safe(slash + 1); - if (errno) - return false; - - switch (prefix->addr.af) { - case AF_INET: - if (plen > 32) - return false; - break; - - case AF_INET6: - if (plen > 128) - return false; - break; - - default: - assert(false); - __builtin_unreachable(); - } - - prefix->plen = plen; - - // TODO: Implement allow_host - - return true; -} - -static bool process_section_device(device_common_t *device, struct json_object *section) { - return true; -} - -static bool process_section_static(device_common_t *device, struct json_object *section) { - struct json_object *addresses = neco_json_get_value(section, "addresses", json_type_array); - if (addresses) { - for (size_t i = 0; i < json_object_array_length(addresses); i++) { - struct json_object *address = json_object_array_get_idx(addresses, i); - if (!json_object_is_type(address, json_type_string)) { - fprintf(stderr, "interface: static: invalid address entry of type %s\n", json_type_to_name(json_object_get_type(address))); - continue; - } - - ipaddr_prefix_t p; - if (!parse_prefix(&p, json_object_get_string(address), true)) { - fprintf(stderr, "interface: static: unable to parse Address %s\n", json_object_get_string(address)); - break; - } - - if (!VECTOR_ADD(device->addrs, p)) { - fprintf(stderr, "interface: static: adding address failed\n"); - return false; - } - } - } - - return true; -} - -static bool process_section_bridge(device_common_t *device, struct json_object *section) { - const char *master = neco_json_get_string(section, "master"); - if (master) - strncpy(device->master, master, sizeof(device->master)-1); - - return true; -} - -bool device_common_process_config(device_common_t *device, struct json_object *config) { - struct json_object *sec_device = neco_json_get_value(config, "device", json_type_object); - if (sec_device) { - if (!process_section_device(device, sec_device)) - return false; - } - - struct json_object *sec_static = neco_json_get_value(config, "static", json_type_object); - if (sec_static) { - if (!process_section_static(device, sec_static)) - return false; - } - - struct json_object *sec_bridge = neco_json_get_value(config, "bridge", json_type_object); - if (sec_bridge) { - if (!process_section_bridge(device, sec_bridge)) - return false; - } - - return true; -} - -static bool device_common_set_link_flags(unsigned ifindex, unsigned change, unsigned flags) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - - struct mnl_socket *nl = nl_socket(); - - struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = RTM_SETLINK; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - int seq = nlh->nlmsg_seq = nl_seq(); - - struct ifinfomsg *ifi = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifi)); - ifi->ifi_index = ifindex; - ifi->ifi_family = AF_UNSPEC; - - ifi->ifi_change = change; - ifi->ifi_flags = flags; - - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { - perror("mnl_socket_sendto"); - return false; - } - - int ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) { - perror("mnl_socket_recvfrom"); - return false; - } - - ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL); - if (ret == -1) { - perror("mnl_cb_run"); - return false; - } - - return true; -} - -static bool device_common_set_link_state(unsigned ifindex, bool up) { - return device_common_set_link_flags(ifindex, IFF_UP, up ? IFF_UP : 0); -} - -static bool device_common_set_ipaddr(unsigned ifindex, ipaddr_prefix_t *addr, bool add) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - - struct mnl_socket *nl = nl_socket(); - - struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = add ? RTM_NEWADDR : RTM_DELADDR; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - if (add) - nlh->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - - int seq = nlh->nlmsg_seq = nl_seq(); - - struct ifaddrmsg *ifa = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifa)); - ifa->ifa_index = ifindex; - ifa->ifa_family = addr->addr.af; - - ifa->ifa_prefixlen = addr->plen; - - switch (addr->addr.af) { - case AF_INET: - mnl_attr_put(nlh, IFA_LOCAL, 4, &addr->addr.addr4); - break; - - case AF_INET6: - mnl_attr_put(nlh, IFA_LOCAL, 16, &addr->addr.addr6); - break; - - default: - errno = EINVAL; - return false; - } - - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { - perror("mnl_socket_sendto"); - return false; - } - - int ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) { - perror("mnl_socket_recvfrom"); - return false; - } - - ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL); - if (ret == -1) { - perror("mnl_cb_run"); - return false; - } - - return true; -} - -static bool device_common_set_master(unsigned ifindex, unsigned master) { - char buf[MNL_SOCKET_BUFFER_SIZE]; - - struct mnl_socket *nl = nl_socket(); - - struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf); - nlh->nlmsg_type = RTM_SETLINK; - nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - int seq = nlh->nlmsg_seq = nl_seq(); - - struct ifinfomsg *ifi = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifi)); - ifi->ifi_index = ifindex; - ifi->ifi_family = AF_UNSPEC; - - mnl_attr_put_u32(nlh, IFLA_MASTER, master); - - if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { - perror("mnl_socket_sendto"); - return false; - } - - int ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); - if (ret == -1) { - perror("mnl_socket_recvfrom"); - return false; - } - - ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(nl), NULL, NULL); - if (ret == -1) { - perror("mnl_cb_run"); - return false; - } - - return true; -} - -void device_common_init(device_common_t *device, int ifindex) { - if (*device->master) { - unsigned master = if_nametoindex(device->master); - if (!master) - return; - - device_common_set_master(ifindex, master); - } - - device_common_set_link_state(ifindex, true); - - if (!*device->master) { - for (size_t i = 0; i < VECTOR_LEN(device->addrs); i++) - device_common_set_ipaddr(ifindex, &VECTOR_INDEX(device->addrs, i), true); - } -} - -void device_common_release(device_common_t *device, int ifindex) { - if (!*device->master) { - for (size_t i = 0; i < VECTOR_LEN(device->addrs); i++) - device_common_set_ipaddr(ifindex, &VECTOR_INDEX(device->addrs, i), false); - } - - device_common_set_link_state(ifindex, false); - - if (*device->master) - device_common_set_master(ifindex, 0); -} diff --git a/src/device-common.h b/src/device-common.h deleted file mode 100644 index dc0fe28..0000000 --- a/src/device-common.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include "device.h" -#include "vector.h" - -#include -#include -#include - -typedef struct _ipaddr { - int af; - union { - struct in_addr addr4; - struct in6_addr addr6; - }; -} ipaddr_t; - -typedef struct _ipprefix { - ipaddr_t addr; - uint8_t plen; -} ipaddr_prefix_t; - -typedef VECTOR(ipaddr_prefix_t) ipaddr_prefix_vector_t; - -typedef struct _device_common { - struct ether_addr macaddr; - uint16_t mtu; - - ipaddr_prefix_vector_t addrs; - char master[IF_NAMESIZE]; -} device_common_t; - -bool device_common_process_config(device_common_t *device, struct json_object *config); - -void device_common_init(device_common_t *device, int ifindex); -void device_common_release(device_common_t *device, int ifindex); diff --git a/src/device-interface.c b/src/device-interface.c deleted file mode 100644 index 1add2b2..0000000 --- a/src/device-interface.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "device-common.h" -#include "util.h" -#include "vector.h" - -#include -#include -#include - -#include - -static device_type_t device_type_interface; - -typedef struct _device_interface { - device_t device; - device_common_t common; -} device_interface_t; - -static void interface_free(device_t *dev) { - device_interface_t *iface = container_of(dev, device_interface_t, device); - - VECTOR_FREE(iface->common.addrs); - free(NODE_NAME(dev)); - free(iface); -} - -static device_t * interface_process_config(const char *name, struct json_object *config) { - device_interface_t *iface = calloc(1, sizeof(*iface)); - if (!iface) - return NULL; - - device_t *dev = &iface->device; - dev->type = &device_type_interface; - - NODE_NAME(dev) = strdup(name); - if (!NODE_NAME(dev)) { - free(iface); - return NULL; - } - - if (!device_common_process_config(&iface->common, config)) - goto err; - - return dev; - -err: - interface_free(dev); - return NULL; -} - -static void interface_init(device_t *dev) { - device_interface_t *iface = container_of(dev, device_interface_t, device); - - unsigned ifindex = if_nametoindex(NODE_NAME(dev)); - if (!ifindex) - return; - - device_common_init(&iface->common, ifindex); -} - -static void interface_update(device_t *dev) { -} - -static void interface_release(device_t *dev) { - device_interface_t *iface = container_of(dev, device_interface_t, device); - - unsigned ifindex = if_nametoindex(NODE_NAME(dev)); - if (!ifindex) - return; - - device_common_release(&iface->common, ifindex); -} - -static device_type_t device_type_interface = { - .process_config = interface_process_config, - .free = interface_free, - - .init = interface_init, - .update = interface_update, - .release = interface_release, -}; - -__attribute__((constructor)) -static void interface_constructor(void) { - register_device_type("interface", &device_type_interface); -} diff --git a/src/device.c b/src/device.c deleted file mode 100644 index a773036..0000000 --- a/src/device.c +++ /dev/null @@ -1,15 +0,0 @@ -#include "device.h" -#include "util.h" - -#include - -AVL_TREE(device_types, avl_strcmp, false, NULL); - -void register_device_type(const char *name, device_type_t *device_type) { - NODE_NAME(device_type) = (char *)name; - avl_insert(&device_types, &device_type->node); -} - -const device_type_t * get_device_type(const char *name) { - return avl_find_element(&device_types, name, (device_type_t *)NULL, node); -} diff --git a/src/device.h b/src/device.h deleted file mode 100644 index e44c695..0000000 --- a/src/device.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include - -extern struct avl_tree device_types; - -typedef struct _device_type device_type_t; - -typedef struct _device { - struct avl_node node; - const device_type_t *type; -} device_t; - -struct _device_type { - struct avl_node node; - device_t * (*process_config)(const char *name, struct json_object *config); - void (*free)(device_t *device); - - void (*init)(device_t *device); - void (*update)(device_t *device); - void (*release)(device_t *device); -}; - -void register_device_type(const char *name, device_type_t *device_type); -const device_type_t * get_device_type(const char *name); diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..4283396 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,53 @@ +#![no_main] +#![no_std] +#![feature(alloc_error_handler)] + +mod system_alloc; + +extern crate alloc; +use libc::cstr; +use safe_libc as libc; + +use core::fmt::Write; + +#[no_mangle] +pub extern "C" fn main(_nargs: libc::c_int, _args: *const *const libc::c_char) -> libc::c_int { + let mut stdout = libc::stdio::stdout(); + + { + let foo = cstr!("Foo!\n"); + let _ = stdout.puts(foo); + } + + { + let x = libc::string::CString::from("foo"); + let l = x.len(); + let y = x.into_raw(); + let z = unsafe { alloc::boxed::Box::from_raw(core::ptr::slice_from_raw_parts_mut(y, l)) }; + let _ = writeln!(stdout, "Foo: {} {} {}", z[0], z[1], z[2]); + } + + { + let x = libc::string::CString::from("bar"); + let _ = stdout.puts(&x); + } + + { + let b = alloc::boxed::Box::new(42); + let _ = writeln!(stdout, "Bar: {}", b); + } + + { + let x = alloc::boxed::Box::new(()); + let _ = writeln!(stdout, "Box: {:?}", x); + } + + 0 +} + +#[cfg(not(test))] +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + let _ = writeln!(libc::stdio::stderr(), "Panic: {}", info); + unsafe { libc::abort() } +} diff --git a/src/meson.build b/src/meson.build deleted file mode 100644 index 3cc830c..0000000 --- a/src/meson.build +++ /dev/null @@ -1,19 +0,0 @@ -src = [ - 'neco.c', - 'config-load.c', - 'config-process.c', - 'device.c', - 'device-bridge.c', - 'device-common.c', - 'device-interface.c', - 'netlink.c', - 'vector.c', -] - -dep = [ - libjson_c_dep, - libmnl_dep, - libubox_dep, -] - -executable('neco', sources: src, dependencies: dep) diff --git a/src/neco.c b/src/neco.c deleted file mode 100644 index 4e4d297..0000000 --- a/src/neco.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "config-load.h" -#include "netlink.h" - -int main(int argc, char *argv[]) { - if (!nl_init()) - return 1; - - read_config(argv[1]); - - nl_deinit(); - - return 0; -} diff --git a/src/netlink.c b/src/netlink.c deleted file mode 100644 index ec9c935..0000000 --- a/src/netlink.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "netlink.h" - -#include - -static struct mnl_socket *nl; -static uint32_t seq; - -bool nl_init(void) { - nl = mnl_socket_open(NETLINK_ROUTE); - if (nl == NULL) { - perror("mnl_socket_open"); - return false; - } - - if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { - perror("mnl_socket_bind"); - nl_deinit(); - return false; - } - - return true; -} - -void nl_deinit(void) { - if (!nl) - return; - - mnl_socket_close(nl); - nl = NULL; -} - -struct mnl_socket * nl_socket(void) { - return nl; -} - -uint32_t nl_seq(void) { - return seq++; -} diff --git a/src/netlink.h b/src/netlink.h deleted file mode 100644 index 6529e92..0000000 --- a/src/netlink.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include - -#include -#include - -bool nl_init(void); -void nl_deinit(void); - -struct mnl_socket * nl_socket(void); -uint32_t nl_seq(void); diff --git a/src/system_alloc.rs b/src/system_alloc.rs new file mode 100644 index 0000000..7c0bac9 --- /dev/null +++ b/src/system_alloc.rs @@ -0,0 +1,22 @@ +use safe_libc as libc; + +struct System; + +unsafe impl alloc::alloc::GlobalAlloc for System { + unsafe fn alloc(&self, layout: alloc::alloc::Layout) -> *mut u8 { + libc::memalign(layout.align(), layout.size()).cast() + } + + unsafe fn dealloc(&self, ptr: *mut u8, _layout: alloc::alloc::Layout) { + libc::free(ptr.cast()); + } +} + +#[global_allocator] +static SYSTEM_ALLOC: System = System; + +#[cfg(not(test))] +#[alloc_error_handler] +fn alloc_error(_: core::alloc::Layout) -> ! { + panic!("allocation failure"); +} diff --git a/src/util.h b/src/util.h deleted file mode 100644 index 2e60467..0000000 --- a/src/util.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - - -#define NODE_NAME(c) (*(char **)&(c)->node.key) - - -static inline struct json_object * neco_json_get_value( - struct json_object *obj, - const char *key, - enum json_type type -) { - struct json_object *value; - if (!json_object_object_get_ex(obj, key, &value)) - return NULL; - if (!json_object_is_type(value, type)) - return NULL; - - return value; -} - -static inline const char * neco_json_get_string(struct json_object *obj, const char *key) { - struct json_object *value = neco_json_get_value(obj, key, json_type_string); - if (!value) - return NULL; - - return json_object_get_string(value); -} diff --git a/src/vector.c b/src/vector.c deleted file mode 100644 index 41cd0cc..0000000 --- a/src/vector.c +++ /dev/null @@ -1,114 +0,0 @@ -/** - \file - - Typesafe dynamically sized arrays -*/ - - -#include "vector.h" - -#include -#include -#include - -/** The minimum number of elements to allocate even when fewer elements are used */ -#define MIN_VECTOR_ALLOC 4 - -/** - Multiplies two size_t values, checking for overflows - - Both arguments are limited to the size of a uint32_t (to keep the check simple) - - Returns SIZE_MAX and sets errno on failure. -*/ -static inline size_t mul_check(size_t members, size_t size) { - uint64_t v = (uint64_t)members * size; - - if (members > UINT32_MAX || size > UINT32_MAX || v > SIZE_MAX) { - errno = EOVERFLOW; - return SIZE_MAX; - } - - return v; -} - -/** - Reallocates a block of memory for an array on the heap - - May fail with EOVERFLOW (when members or size does not fit into a uint32_t, - or their product does not fit into a size_t) or ENOMEM. -*/ -static inline void * realloc_array(void *ptr, size_t members, size_t size) { - errno = 0; - size_t array_size = mul_check(members, size); - if (errno) - return NULL; - - return realloc(ptr, array_size); -} - -/** - Resizes a vector - - Vector allocations are always powers of 2. - - Internal function, use VECTOR_RESIZE() instead. -*/ -bool _vector_resize(vector_desc_t *desc, void **data, size_t n, size_t elemsize) { - desc->length = n; - - size_t alloc = desc->allocated; - - if (!alloc) { - alloc = MIN_VECTOR_ALLOC; - n = n*3/2; - } - - while (alloc < n) { - alloc <<= 1; - if (!alloc) { - errno = ENOMEM; - return false; - } - } - - if (alloc != desc->allocated) { - desc->allocated = alloc; - void *tmp = realloc_array(*data, alloc, elemsize); - if (!tmp) - return false; - - *data = tmp; - } - - return true; -} - -/** - Inserts an element into a vector - - Internal function, use VECTOR_INSERT() and VECTOR_ADD() instead. -*/ -bool _vector_insert(vector_desc_t *desc, void **data, void *element, size_t pos, size_t elemsize) { - if (!_vector_resize(desc, data, desc->length+1, elemsize)) - return false; - - void *p = *data + pos*elemsize; - - memmove(p+elemsize, p, (desc->length-pos-1)*elemsize); - memcpy(p, element, elemsize); - - return true; -} - -/** - Deletes an element from a vector - - Internal function, use VECTOR_DELETE() instead. -*/ -void _vector_delete(vector_desc_t *desc, void **data, size_t pos, size_t elemsize) { - void *p = *data + pos*elemsize; - memmove(p, p+elemsize, (desc->length-pos-1)*elemsize); - - desc->length--; -} diff --git a/src/vector.h b/src/vector.h deleted file mode 100644 index 02ea804..0000000 --- a/src/vector.h +++ /dev/null @@ -1,113 +0,0 @@ -/** - \file - - Typesafe dynamically sized arrays -*/ - - -#pragma once - -#include -#include - -/** A vector descriptor */ -typedef struct _vector_desc { - size_t allocated; /**< The number of elements currently allocated */ - size_t length; /**< The actual number of elements in the vector */ -} vector_desc_t; - -/** - A type for a vector of \e type elements - - \hideinitializer -*/ -#define VECTOR(type) struct { \ - vector_desc_t desc; \ - type *data; \ -} - -bool _vector_resize(vector_desc_t *desc, void **data, size_t n, size_t elemsize); -bool _vector_insert(vector_desc_t *desc, void **data, void *element, size_t pos, size_t elemsize); -void _vector_delete(vector_desc_t *desc, void **data, size_t pos, size_t elemsize); - -/** - Resizes the vector \e a to \e n elements - - \hideinitializer -*/ -#define VECTOR_RESIZE(v, n) ({ \ - __typeof__(v) *_v = &(v); \ - _vector_resize(&_v->desc, (void **)&_v->data, (n), sizeof(*_v->data)); \ -}) - -/** - Frees all resources used by the vector \e v - - \hideinitializer -*/ -#define VECTOR_FREE(v) free((v).data) - -/** - Returns the number of elements in the vector \e v - - \hideinitializer -*/ -#define VECTOR_LEN(v) ((v).desc.length) - -/** - Returns the element with index \e i in the vector \e v - - \hideinitializer -*/ -#define VECTOR_INDEX(v, i) ((v).data[i]) - -/** - Returns a pointer to the vector elements of \e v - - \hideinitializer -*/ -#define VECTOR_DATA(v) ((v).data) - -/** - Inserts the element \e elem at index \e pos of vector \e v - - \hideinitializer -*/ -#define VECTOR_INSERT(v, elem, pos) ({ \ - __typeof__(v) *_v = &(v); \ - __typeof__(*_v->data) _e = (elem); \ - _vector_insert(&_v->desc, (void **)&_v->data, &_e, (pos), sizeof(_e)); \ -}) - -/** - Adds the element \e elem at the end of vector \e v - - \hideinitializer -*/ -#define VECTOR_ADD(v, elem) ({ \ - __typeof__(v) *_v = &(v); \ - __typeof__(*_v->data) _e = (elem); \ - _vector_insert(&_v->desc, (void **)&_v->data, &_e, _v->desc.length, sizeof(_e)); \ -}) - -/** - Deletes the element at index \e pos of vector \e v - - \hideinitializer -*/ -#define VECTOR_DELETE(v, pos) ({ \ - __typeof__(v) *_v = &(v); \ - _vector_delete(&_v->desc, (void **)&_v->data, (pos), sizeof(*_v->data)); \ -}) - -/** - Performs a binary search on the vector \e v, returning a pointer to a matching vector element - - \hideinitializer -*/ -#define VECTOR_BSEARCH(key, v, cmp) ({ \ - __typeof__(v) *_v = &(v); \ - const __typeof__(*_v->data) *_key = (key); \ - int (*_cmp)(__typeof__(_key), __typeof__(_key)) = (cmp); \ - (__typeof__(_v->data))bsearch(_key, _v->data, _v->desc.length, sizeof(*_v->data), (int (*)(const void *, const void *))_cmp); \ -})