diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-04-19 20:46:50 +0200 |
|---|---|---|
| committer | Christian Breunig <christian@breunig.cc> | 2026-04-19 20:50:41 +0200 |
| commit | f3a21109778fea1f3c2d7ab1afa0c5e0f75483a8 (patch) | |
| tree | 2c79044fa15d6c0c62d115327254b1f9089c9032 /src/ocaml/completion | |
| parent | 67b68bd9893ad3a39af53ceee856ce5c61ed0638 (diff) | |
| parent | 1fd60b557ea15a9129829d7e8a9395c9b656012a (diff) | |
| download | vyos-1x-f3a21109778fea1f3c2d7ab1afa0c5e0f75483a8.tar.gz vyos-1x-f3a21109778fea1f3c2d7ab1afa0c5e0f75483a8.zip | |
Merge branch 'current' of github.com:vyos/vyos-utils into vyos-utils-merge
* 'current' of github.com:vyos/vyos-utils: (65 commits)
T8269: add option to silence output of individual validators
T8306: update package version
vyos-op-run: T8306: add error messages for system exceptions
vyos-op-run: T8306: improve execution logic logging
vyos-op-run: T8301: improve the security of UID check and setuid logic
T8110: "list_interfaces --bondable" must not return VLAN subinterfaces
vyos-op-run: T7901: skip permission checks if the user is root
vyos-op-run: T8005: sanitize environment variables to prevent malicious variable injection
T7878: conflict check updated to use mergify
T7878: conflict check updated to use mergify
T7899: virtual-ethernet interfaces support broadcasts
Debian: T7899: bump dh compat version
T7758: add missing case to allow repeated option --type
T7758: allow repeated option --type in list_interfaces
vyos-op-run: T7745: add a command permission checking mechanism
op-mode: T7583: add a new operational command runner
T7644: mirror workflow refactoring rollout
T7579: fix of the run trigger for CLA
T7579: added workflow for CLA
validators: T6622: Radix-aware numeric validation
...
Diffstat (limited to 'src/ocaml/completion')
| -rw-r--r-- | src/ocaml/completion/list_interfaces/func.ml | 1 | ||||
| -rw-r--r-- | src/ocaml/completion/list_interfaces/func.mli | 1 | ||||
| -rw-r--r-- | src/ocaml/completion/list_interfaces/iface.c | 38 | ||||
| -rw-r--r-- | src/ocaml/completion/list_interfaces/list_interfaces.ml | 143 |
4 files changed, 183 insertions, 0 deletions
diff --git a/src/ocaml/completion/list_interfaces/func.ml b/src/ocaml/completion/list_interfaces/func.ml new file mode 100644 index 000000000..13e1860d9 --- /dev/null +++ b/src/ocaml/completion/list_interfaces/func.ml @@ -0,0 +1 @@ +external list_interfaces: unit -> string list = "interface_list" diff --git a/src/ocaml/completion/list_interfaces/func.mli b/src/ocaml/completion/list_interfaces/func.mli new file mode 100644 index 000000000..b16d37354 --- /dev/null +++ b/src/ocaml/completion/list_interfaces/func.mli @@ -0,0 +1 @@ +external list_interfaces : unit -> string list = "interface_list" diff --git a/src/ocaml/completion/list_interfaces/iface.c b/src/ocaml/completion/list_interfaces/iface.c new file mode 100644 index 000000000..bf2f0250e --- /dev/null +++ b/src/ocaml/completion/list_interfaces/iface.c @@ -0,0 +1,38 @@ +/* + * Simple wrapper of getifaddrs for OCaml list of interfaces + */ +#include <ifaddrs.h> +#include <caml/mlvalues.h> +#include <caml/memory.h> +#include <caml/alloc.h> + +CAMLprim value interface_list(value unit) { + struct ifaddrs *ifaddr; + struct ifaddrs *ifa; + + CAMLparam1( unit ); + CAMLlocal2( cli, cons ); + + cli = Val_emptylist; + + if (getifaddrs(&ifaddr) == -1) { + CAMLreturn(cli); + } + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_name == NULL) + continue; + + CAMLlocal1( ml_s ); + cons = caml_alloc(2, 0); + + ml_s = caml_copy_string(ifa->ifa_name); + Store_field( cons, 0, ml_s ); + Store_field( cons, 1, cli ); + + cli = cons; + } + + freeifaddrs(ifaddr); + + CAMLreturn(cli); +} diff --git a/src/ocaml/completion/list_interfaces/list_interfaces.ml b/src/ocaml/completion/list_interfaces/list_interfaces.ml new file mode 100644 index 000000000..b76afd4c1 --- /dev/null +++ b/src/ocaml/completion/list_interfaces/list_interfaces.ml @@ -0,0 +1,143 @@ +(* + *) +let intf_types = ref [] +let broadcast = ref false +let bridgeable = ref false +let bondable = ref false +let no_vlan = ref false + +let args = [ + ("--type", Arg.String (fun s -> intf_types := (s :: !intf_types)), "List interfaces of specified type"); + ("--broadcast", Arg.Unit (fun () -> broadcast := true), "List broadcast interfaces"); + ("--bridgeable", Arg.Unit (fun () -> bridgeable := true), "List bridgeable interfaces"); + ("--bondable", Arg.Unit (fun () -> bondable := true), "List bondable interfaces"); + ("--no-vlan-subinterfaces", Arg.Unit (fun () -> no_vlan := true), "List only parent interfaces"); +] +let usage = Printf.sprintf "Usage: %s [OPTIONS] <number>" Sys.argv.(0) + +let () = Arg.parse args (fun _ -> ()) usage + +let type_to_prefix it = + match it with + | "" -> "" + | "bonding" -> "bond" + | "bridge" -> "br" + | "dummy" -> "dum" + | "ethernet" -> "eth" + | "geneve" -> "gnv" + | "input" -> "ifb" + | "l2tpeth" -> "l2tpeth" + | "loopback" -> "lo" + | "macsec" -> "macsec" + | "openvpn" -> "vtun" + | "pppoe" -> "pppoe" + | "pseudo-ethernet" -> "peth" + | "sstpc" -> "sstpc" + | "tunnel" -> "tun" + | "virtual-ethernet" -> "veth" + | "vti" -> "vti" + | "vxlan" -> "vxlan" + | "wireguard" -> "wg" + | "wireless" -> "wlan" + | "wwan" -> "wwan" + | _ -> "" + +(* filter_section to match the constraint of python.vyos.ifconfig.section + *) +let rx = Pcre2.regexp {|\d(\d|v|\.)*$|} + +let filter_section s = + let r = Pcre2.qreplace_first ~rex:rx ~templ:"" s in + match r with + |"bond"|"br"|"dum"|"eth"|"gnv"|"ifb"|"l2tpeth"|"lo"|"macsec" -> true + |"peth"|"pppoe"|"sstpc"|"tun"|"veth"|"vti"|"vtun"|"vxlan"|"wg"|"wlan"|"wwan" -> true + | _ -> false + +let filter_from_prefix p s = + let pattern = Printf.sprintf "^%s(.*)$" p + in + try + let _ = Pcre2.exec ~pat:pattern s in + true + with Not_found -> false + +let filter_from_type it = + let pre = type_to_prefix it in + match pre with + | "" -> None + | _ -> Some (filter_from_prefix pre) + +let filter_broadcast s = + let pattern = {|^(bond|br|tun|vtun|eth|gnv|peth|macsec|veth|vxlan|wwan|wlan)(.*)$|} + in + try + let _ = Pcre2.exec ~pat:pattern s in + true + with Not_found -> false + +let filter_bridgeable s = + let pattern = {|^(bond|eth|gnv|l2tpeth|lo|tun|veth|vtun|vxlan|wlan)(.*)$|} + in + try + let _ = Pcre2.exec ~pat:pattern s in + true + with Not_found -> false + +let filter_bondable s = + let pattern = {|^(eth|lan|eno|ens)[A-Za-z0-9_-]*$|} + in + try + let _ = Pcre2.exec ~pat:pattern s in + true + with Not_found -> false + +let filter_no_vlan s = + let pattern = {|^([^.]+)(\.\d+)+$|} + in + try + let _ = Pcre2.exec ~pat:pattern s in + false + with Not_found -> true + +let get_interfaces_by_type out intf_type = + let fltr = + if String.length(intf_type) > 0 then + filter_from_type intf_type + else None + in + let l = Func.list_interfaces () in + let res = List.sort_uniq compare l in + let res = + if !broadcast then List.filter filter_broadcast res + else res + in + let res = + if !bridgeable then List.filter filter_bridgeable res + else res + in + let res = + if !bondable then List.filter filter_bondable res + else res + in + let res = + if !no_vlan then List.filter filter_no_vlan res + else res + in + let add_out = + let res = List.filter filter_section res in + match fltr with + | Some f -> List.filter f res + | None -> res + in List.append out add_out + +let get_interfaces = + let types = List.rev !intf_types in + if types <> [] then + List.fold_left get_interfaces_by_type [] types + else + get_interfaces_by_type [] "" + +let () = + let res = get_interfaces in + List.iter (Printf.printf "%s ") res; + Printf.printf "\n" |
