style: add clang-format, ktlint, editorconfig and format all code

- Add .editorconfig with ktlint config (disable wildcard-import rule,
  allow PascalCase for @Composable functions)
- Add kmod/.clang-format from upstream kernel tree
- Run clang-format on vpnhide_kmod.c (kernel coding style)
- Run ktlint --format on all Kotlin files (lsposed + test-app)
This commit is contained in:
okhsunrog 2026-04-12 23:26:36 +03:00
parent ca35183084
commit e2d41dea13
7 changed files with 1065 additions and 284 deletions

14
.editorconfig Normal file
View file

@ -0,0 +1,14 @@
root = true
[*]
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.kt]
# Compose @Composable functions use PascalCase by convention
ktlint_function_naming_ignore_when_annotated_with = Composable
# Wildcard imports are idiomatic for Compose (androidx.compose.*)
ktlint_standard_no-wildcard-imports = disabled

684
kmod/.clang-format Normal file
View file

@ -0,0 +1,684 @@
# SPDX-License-Identifier: GPL-2.0
#
# clang-format configuration file. Intended for clang-format >= 11.
#
# For more information, see:
#
# Documentation/process/clang-format.rst
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
#
---
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
# Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ tools/ \
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
# | LC_ALL=C sort -u
ForEachMacros:
- '__ata_qc_for_each'
- '__bio_for_each_bvec'
- '__bio_for_each_segment'
- '__evlist__for_each_entry'
- '__evlist__for_each_entry_continue'
- '__evlist__for_each_entry_from'
- '__evlist__for_each_entry_reverse'
- '__evlist__for_each_entry_safe'
- '__for_each_mem_range'
- '__for_each_mem_range_rev'
- '__for_each_thread'
- '__hlist_for_each_rcu'
- '__map__for_each_symbol_by_name'
- '__perf_evlist__for_each_entry'
- '__perf_evlist__for_each_entry_reverse'
- '__perf_evlist__for_each_entry_safe'
- '__rq_for_each_bio'
- '__shost_for_each_device'
- 'apei_estatus_for_each_section'
- 'ata_for_each_dev'
- 'ata_for_each_link'
- 'ata_qc_for_each'
- 'ata_qc_for_each_raw'
- 'ata_qc_for_each_with_internal'
- 'ax25_for_each'
- 'ax25_uid_for_each'
- 'bio_for_each_bvec'
- 'bio_for_each_bvec_all'
- 'bio_for_each_folio_all'
- 'bio_for_each_integrity_vec'
- 'bio_for_each_segment'
- 'bio_for_each_segment_all'
- 'bio_list_for_each'
- 'bip_for_each_vec'
- 'bond_for_each_slave'
- 'bond_for_each_slave_rcu'
- 'bpf__perf_for_each_map'
- 'bpf__perf_for_each_map_named'
- 'bpf_for_each_spilled_reg'
- 'bpf_object__for_each_map'
- 'bpf_object__for_each_program'
- 'bpf_object__for_each_safe'
- 'bpf_perf_object__for_each'
- 'btree_for_each_safe128'
- 'btree_for_each_safe32'
- 'btree_for_each_safe64'
- 'btree_for_each_safel'
- 'card_for_each_dev'
- 'cgroup_taskset_for_each'
- 'cgroup_taskset_for_each_leader'
- 'cpufreq_for_each_efficient_entry_idx'
- 'cpufreq_for_each_entry'
- 'cpufreq_for_each_entry_idx'
- 'cpufreq_for_each_valid_entry'
- 'cpufreq_for_each_valid_entry_idx'
- 'css_for_each_child'
- 'css_for_each_descendant_post'
- 'css_for_each_descendant_pre'
- 'damon_for_each_region'
- 'damon_for_each_region_safe'
- 'damon_for_each_scheme'
- 'damon_for_each_scheme_safe'
- 'damon_for_each_target'
- 'damon_for_each_target_safe'
- 'data__for_each_file'
- 'data__for_each_file_new'
- 'data__for_each_file_start'
- 'device_for_each_child_node'
- 'displayid_iter_for_each'
- 'dma_fence_array_for_each'
- 'dma_fence_chain_for_each'
- 'dma_fence_unwrap_for_each'
- 'dma_resv_for_each_fence'
- 'dma_resv_for_each_fence_unlocked'
- 'do_for_each_ftrace_op'
- 'drm_atomic_crtc_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane'
- 'drm_atomic_crtc_state_for_each_plane_state'
- 'drm_atomic_for_each_plane_damage'
- 'drm_client_for_each_connector_iter'
- 'drm_client_for_each_modeset'
- 'drm_connector_for_each_possible_encoder'
- 'drm_for_each_bridge_in_chain'
- 'drm_for_each_connector_iter'
- 'drm_for_each_crtc'
- 'drm_for_each_crtc_reverse'
- 'drm_for_each_encoder'
- 'drm_for_each_encoder_mask'
- 'drm_for_each_fb'
- 'drm_for_each_legacy_plane'
- 'drm_for_each_plane'
- 'drm_for_each_plane_mask'
- 'drm_for_each_privobj'
- 'drm_mm_for_each_hole'
- 'drm_mm_for_each_node'
- 'drm_mm_for_each_node_in_range'
- 'drm_mm_for_each_node_safe'
- 'dsa_switch_for_each_available_port'
- 'dsa_switch_for_each_cpu_port'
- 'dsa_switch_for_each_port'
- 'dsa_switch_for_each_port_continue_reverse'
- 'dsa_switch_for_each_port_safe'
- 'dsa_switch_for_each_user_port'
- 'dsa_tree_for_each_user_port'
- 'dso__for_each_symbol'
- 'dsos__for_each_with_build_id'
- 'elf_hash_for_each_possible'
- 'elf_section__for_each_rel'
- 'elf_section__for_each_rela'
- 'elf_symtab__for_each_symbol'
- 'evlist__for_each_cpu'
- 'evlist__for_each_entry'
- 'evlist__for_each_entry_continue'
- 'evlist__for_each_entry_from'
- 'evlist__for_each_entry_reverse'
- 'evlist__for_each_entry_safe'
- 'flow_action_for_each'
- 'for_each_acpi_dev_match'
- 'for_each_active_dev_scope'
- 'for_each_active_drhd_unit'
- 'for_each_active_iommu'
- 'for_each_aggr_pgid'
- 'for_each_available_child_of_node'
- 'for_each_bench'
- 'for_each_bio'
- 'for_each_board_func_rsrc'
- 'for_each_btf_ext_rec'
- 'for_each_btf_ext_sec'
- 'for_each_bvec'
- 'for_each_card_auxs'
- 'for_each_card_auxs_safe'
- 'for_each_card_components'
- 'for_each_card_dapms'
- 'for_each_card_pre_auxs'
- 'for_each_card_prelinks'
- 'for_each_card_rtds'
- 'for_each_card_rtds_safe'
- 'for_each_card_widgets'
- 'for_each_card_widgets_safe'
- 'for_each_cgroup_storage_type'
- 'for_each_child_of_node'
- 'for_each_clear_bit'
- 'for_each_clear_bit_from'
- 'for_each_clear_bitrange'
- 'for_each_clear_bitrange_from'
- 'for_each_cmd'
- 'for_each_cmsghdr'
- 'for_each_collection'
- 'for_each_comp_order'
- 'for_each_compatible_node'
- 'for_each_component_dais'
- 'for_each_component_dais_safe'
- 'for_each_console'
- 'for_each_cpu'
- 'for_each_cpu_and'
- 'for_each_cpu_not'
- 'for_each_cpu_wrap'
- 'for_each_dapm_widgets'
- 'for_each_dedup_cand'
- 'for_each_dev_addr'
- 'for_each_dev_scope'
- 'for_each_dma_cap_mask'
- 'for_each_dpcm_be'
- 'for_each_dpcm_be_rollback'
- 'for_each_dpcm_be_safe'
- 'for_each_dpcm_fe'
- 'for_each_drhd_unit'
- 'for_each_dss_dev'
- 'for_each_efi_memory_desc'
- 'for_each_efi_memory_desc_in_map'
- 'for_each_element'
- 'for_each_element_extid'
- 'for_each_element_id'
- 'for_each_endpoint_of_node'
- 'for_each_event'
- 'for_each_event_tps'
- 'for_each_evictable_lru'
- 'for_each_fib6_node_rt_rcu'
- 'for_each_fib6_walker_rt'
- 'for_each_free_mem_pfn_range_in_zone'
- 'for_each_free_mem_pfn_range_in_zone_from'
- 'for_each_free_mem_range'
- 'for_each_free_mem_range_reverse'
- 'for_each_func_rsrc'
- 'for_each_group_evsel'
- 'for_each_group_member'
- 'for_each_hstate'
- 'for_each_if'
- 'for_each_inject_fn'
- 'for_each_insn'
- 'for_each_insn_prefix'
- 'for_each_intid'
- 'for_each_iommu'
- 'for_each_ip_tunnel_rcu'
- 'for_each_irq_nr'
- 'for_each_lang'
- 'for_each_link_codecs'
- 'for_each_link_cpus'
- 'for_each_link_platforms'
- 'for_each_lru'
- 'for_each_matching_node'
- 'for_each_matching_node_and_match'
- 'for_each_mem_pfn_range'
- 'for_each_mem_range'
- 'for_each_mem_range_rev'
- 'for_each_mem_region'
- 'for_each_member'
- 'for_each_memory'
- 'for_each_migratetype_order'
- 'for_each_missing_reg'
- 'for_each_net'
- 'for_each_net_continue_reverse'
- 'for_each_net_rcu'
- 'for_each_netdev'
- 'for_each_netdev_continue'
- 'for_each_netdev_continue_rcu'
- 'for_each_netdev_continue_reverse'
- 'for_each_netdev_feature'
- 'for_each_netdev_in_bond_rcu'
- 'for_each_netdev_rcu'
- 'for_each_netdev_reverse'
- 'for_each_netdev_safe'
- 'for_each_new_connector_in_state'
- 'for_each_new_crtc_in_state'
- 'for_each_new_mst_mgr_in_state'
- 'for_each_new_plane_in_state'
- 'for_each_new_plane_in_state_reverse'
- 'for_each_new_private_obj_in_state'
- 'for_each_new_reg'
- 'for_each_node'
- 'for_each_node_by_name'
- 'for_each_node_by_type'
- 'for_each_node_mask'
- 'for_each_node_state'
- 'for_each_node_with_cpus'
- 'for_each_node_with_property'
- 'for_each_nonreserved_multicast_dest_pgid'
- 'for_each_of_allnodes'
- 'for_each_of_allnodes_from'
- 'for_each_of_cpu_node'
- 'for_each_of_pci_range'
- 'for_each_old_connector_in_state'
- 'for_each_old_crtc_in_state'
- 'for_each_old_mst_mgr_in_state'
- 'for_each_old_plane_in_state'
- 'for_each_old_private_obj_in_state'
- 'for_each_oldnew_connector_in_state'
- 'for_each_oldnew_crtc_in_state'
- 'for_each_oldnew_mst_mgr_in_state'
- 'for_each_oldnew_plane_in_state'
- 'for_each_oldnew_plane_in_state_reverse'
- 'for_each_oldnew_private_obj_in_state'
- 'for_each_online_cpu'
- 'for_each_online_node'
- 'for_each_online_pgdat'
- 'for_each_path'
- 'for_each_pci_bridge'
- 'for_each_pci_dev'
- 'for_each_pcm_streams'
- 'for_each_physmem_range'
- 'for_each_populated_zone'
- 'for_each_possible_cpu'
- 'for_each_present_cpu'
- 'for_each_prime_number'
- 'for_each_prime_number_from'
- 'for_each_probe_cache_entry'
- 'for_each_process'
- 'for_each_process_thread'
- 'for_each_prop_codec_conf'
- 'for_each_prop_dai_codec'
- 'for_each_prop_dai_cpu'
- 'for_each_prop_dlc_codecs'
- 'for_each_prop_dlc_cpus'
- 'for_each_prop_dlc_platforms'
- 'for_each_property_of_node'
- 'for_each_reg'
- 'for_each_reg_filtered'
- 'for_each_registered_fb'
- 'for_each_requested_gpio'
- 'for_each_requested_gpio_in_range'
- 'for_each_reserved_mem_range'
- 'for_each_reserved_mem_region'
- 'for_each_rtd_codec_dais'
- 'for_each_rtd_components'
- 'for_each_rtd_cpu_dais'
- 'for_each_rtd_dais'
- 'for_each_script'
- 'for_each_sec'
- 'for_each_set_bit'
- 'for_each_set_bit_from'
- 'for_each_set_bitrange'
- 'for_each_set_bitrange_from'
- 'for_each_set_clump8'
- 'for_each_sg'
- 'for_each_sg_dma_page'
- 'for_each_sg_page'
- 'for_each_sgtable_dma_page'
- 'for_each_sgtable_dma_sg'
- 'for_each_sgtable_page'
- 'for_each_sgtable_sg'
- 'for_each_shell_test'
- 'for_each_sibling_event'
- 'for_each_subelement'
- 'for_each_subelement_extid'
- 'for_each_subelement_id'
- 'for_each_sublist'
- 'for_each_subsystem'
- 'for_each_supported_activate_fn'
- 'for_each_supported_inject_fn'
- 'for_each_test'
- 'for_each_thread'
- 'for_each_token'
- 'for_each_unicast_dest_pgid'
- 'for_each_vsi'
- 'for_each_wakeup_source'
- 'for_each_zone'
- 'for_each_zone_zonelist'
- 'for_each_zone_zonelist_nodemask'
- 'func_for_each_insn'
- 'fwnode_for_each_available_child_node'
- 'fwnode_for_each_child_node'
- 'fwnode_graph_for_each_endpoint'
- 'gadget_for_each_ep'
- 'genradix_for_each'
- 'genradix_for_each_from'
- 'hash_for_each'
- 'hash_for_each_possible'
- 'hash_for_each_possible_rcu'
- 'hash_for_each_possible_rcu_notrace'
- 'hash_for_each_possible_safe'
- 'hash_for_each_rcu'
- 'hash_for_each_safe'
- 'hashmap__for_each_entry'
- 'hashmap__for_each_entry_safe'
- 'hashmap__for_each_key_entry'
- 'hashmap__for_each_key_entry_safe'
- 'hctx_for_each_ctx'
- 'hists__for_each_format'
- 'hists__for_each_sort_list'
- 'hlist_bl_for_each_entry'
- 'hlist_bl_for_each_entry_rcu'
- 'hlist_bl_for_each_entry_safe'
- 'hlist_for_each'
- 'hlist_for_each_entry'
- 'hlist_for_each_entry_continue'
- 'hlist_for_each_entry_continue_rcu'
- 'hlist_for_each_entry_continue_rcu_bh'
- 'hlist_for_each_entry_from'
- 'hlist_for_each_entry_from_rcu'
- 'hlist_for_each_entry_rcu'
- 'hlist_for_each_entry_rcu_bh'
- 'hlist_for_each_entry_rcu_notrace'
- 'hlist_for_each_entry_safe'
- 'hlist_for_each_entry_srcu'
- 'hlist_for_each_safe'
- 'hlist_nulls_for_each_entry'
- 'hlist_nulls_for_each_entry_from'
- 'hlist_nulls_for_each_entry_rcu'
- 'hlist_nulls_for_each_entry_safe'
- 'i3c_bus_for_each_i2cdev'
- 'i3c_bus_for_each_i3cdev'
- 'idr_for_each_entry'
- 'idr_for_each_entry_continue'
- 'idr_for_each_entry_continue_ul'
- 'idr_for_each_entry_ul'
- 'in_dev_for_each_ifa_rcu'
- 'in_dev_for_each_ifa_rtnl'
- 'inet_bind_bucket_for_each'
- 'inet_lhash2_for_each_icsk'
- 'inet_lhash2_for_each_icsk_continue'
- 'inet_lhash2_for_each_icsk_rcu'
- 'intlist__for_each_entry'
- 'intlist__for_each_entry_safe'
- 'kcore_copy__for_each_phdr'
- 'key_for_each'
- 'key_for_each_safe'
- 'klp_for_each_func'
- 'klp_for_each_func_safe'
- 'klp_for_each_func_static'
- 'klp_for_each_object'
- 'klp_for_each_object_safe'
- 'klp_for_each_object_static'
- 'kunit_suite_for_each_test_case'
- 'kvm_for_each_memslot'
- 'kvm_for_each_memslot_in_gfn_range'
- 'kvm_for_each_vcpu'
- 'libbpf_nla_for_each_attr'
- 'list_for_each'
- 'list_for_each_codec'
- 'list_for_each_codec_safe'
- 'list_for_each_continue'
- 'list_for_each_entry'
- 'list_for_each_entry_continue'
- 'list_for_each_entry_continue_rcu'
- 'list_for_each_entry_continue_reverse'
- 'list_for_each_entry_from'
- 'list_for_each_entry_from_rcu'
- 'list_for_each_entry_from_reverse'
- 'list_for_each_entry_lockless'
- 'list_for_each_entry_rcu'
- 'list_for_each_entry_reverse'
- 'list_for_each_entry_safe'
- 'list_for_each_entry_safe_continue'
- 'list_for_each_entry_safe_from'
- 'list_for_each_entry_safe_reverse'
- 'list_for_each_entry_srcu'
- 'list_for_each_from'
- 'list_for_each_prev'
- 'list_for_each_prev_safe'
- 'list_for_each_safe'
- 'llist_for_each'
- 'llist_for_each_entry'
- 'llist_for_each_entry_safe'
- 'llist_for_each_safe'
- 'map__for_each_symbol'
- 'map__for_each_symbol_by_name'
- 'map_for_each_event'
- 'map_for_each_metric'
- 'maps__for_each_entry'
- 'maps__for_each_entry_safe'
- 'mci_for_each_dimm'
- 'media_device_for_each_entity'
- 'media_device_for_each_intf'
- 'media_device_for_each_link'
- 'media_device_for_each_pad'
- 'msi_for_each_desc'
- 'nanddev_io_for_each_page'
- 'netdev_for_each_lower_dev'
- 'netdev_for_each_lower_private'
- 'netdev_for_each_lower_private_rcu'
- 'netdev_for_each_mc_addr'
- 'netdev_for_each_uc_addr'
- 'netdev_for_each_upper_dev_rcu'
- 'netdev_hw_addr_list_for_each'
- 'nft_rule_for_each_expr'
- 'nla_for_each_attr'
- 'nla_for_each_nested'
- 'nlmsg_for_each_attr'
- 'nlmsg_for_each_msg'
- 'nr_neigh_for_each'
- 'nr_neigh_for_each_safe'
- 'nr_node_for_each'
- 'nr_node_for_each_safe'
- 'of_for_each_phandle'
- 'of_property_for_each_string'
- 'of_property_for_each_u32'
- 'pci_bus_for_each_resource'
- 'pci_doe_for_each_off'
- 'pcl_for_each_chunk'
- 'pcl_for_each_segment'
- 'pcm_for_each_format'
- 'perf_config_items__for_each_entry'
- 'perf_config_sections__for_each_entry'
- 'perf_config_set__for_each_entry'
- 'perf_cpu_map__for_each_cpu'
- 'perf_evlist__for_each_entry'
- 'perf_evlist__for_each_entry_reverse'
- 'perf_evlist__for_each_entry_safe'
- 'perf_evlist__for_each_evsel'
- 'perf_evlist__for_each_mmap'
- 'perf_hpp_list__for_each_format'
- 'perf_hpp_list__for_each_format_safe'
- 'perf_hpp_list__for_each_sort_list'
- 'perf_hpp_list__for_each_sort_list_safe'
- 'perf_pmu__for_each_hybrid_pmu'
- 'ping_portaddr_for_each_entry'
- 'ping_portaddr_for_each_entry_rcu'
- 'plist_for_each'
- 'plist_for_each_continue'
- 'plist_for_each_entry'
- 'plist_for_each_entry_continue'
- 'plist_for_each_entry_safe'
- 'plist_for_each_safe'
- 'pnp_for_each_card'
- 'pnp_for_each_dev'
- 'protocol_for_each_card'
- 'protocol_for_each_dev'
- 'queue_for_each_hw_ctx'
- 'radix_tree_for_each_slot'
- 'radix_tree_for_each_tagged'
- 'rb_for_each'
- 'rbtree_postorder_for_each_entry_safe'
- 'rdma_for_each_block'
- 'rdma_for_each_port'
- 'rdma_umem_for_each_dma_block'
- 'resort_rb__for_each_entry'
- 'resource_list_for_each_entry'
- 'resource_list_for_each_entry_safe'
- 'rhl_for_each_entry_rcu'
- 'rhl_for_each_rcu'
- 'rht_for_each'
- 'rht_for_each_entry'
- 'rht_for_each_entry_from'
- 'rht_for_each_entry_rcu'
- 'rht_for_each_entry_rcu_from'
- 'rht_for_each_entry_safe'
- 'rht_for_each_from'
- 'rht_for_each_rcu'
- 'rht_for_each_rcu_from'
- 'rq_for_each_bvec'
- 'rq_for_each_segment'
- 'rq_list_for_each'
- 'rq_list_for_each_safe'
- 'scsi_for_each_prot_sg'
- 'scsi_for_each_sg'
- 'sctp_for_each_hentry'
- 'sctp_skb_for_each'
- 'sec_for_each_insn'
- 'sec_for_each_insn_continue'
- 'sec_for_each_insn_from'
- 'shdma_for_each_chan'
- 'shost_for_each_device'
- 'sk_for_each'
- 'sk_for_each_bound'
- 'sk_for_each_entry_offset_rcu'
- 'sk_for_each_from'
- 'sk_for_each_rcu'
- 'sk_for_each_safe'
- 'sk_nulls_for_each'
- 'sk_nulls_for_each_from'
- 'sk_nulls_for_each_rcu'
- 'snd_array_for_each'
- 'snd_pcm_group_for_each_entry'
- 'snd_soc_dapm_widget_for_each_path'
- 'snd_soc_dapm_widget_for_each_path_safe'
- 'snd_soc_dapm_widget_for_each_sink_path'
- 'snd_soc_dapm_widget_for_each_source_path'
- 'strlist__for_each_entry'
- 'strlist__for_each_entry_safe'
- 'sym_for_each_insn'
- 'sym_for_each_insn_continue_reverse'
- 'symbols__for_each_entry'
- 'tb_property_for_each'
- 'tcf_act_for_each_action'
- 'tcf_exts_for_each_action'
- 'udp_portaddr_for_each_entry'
- 'udp_portaddr_for_each_entry_rcu'
- 'usb_hub_for_each_child'
- 'v4l2_device_for_each_subdev'
- 'v4l2_m2m_for_each_dst_buf'
- 'v4l2_m2m_for_each_dst_buf_safe'
- 'v4l2_m2m_for_each_src_buf'
- 'v4l2_m2m_for_each_src_buf_safe'
- 'virtio_device_for_each_vq'
- 'while_for_each_ftrace_op'
- 'xa_for_each'
- 'xa_for_each_marked'
- 'xa_for_each_range'
- 'xa_for_each_start'
- 'xas_for_each'
- 'xas_for_each_conflict'
- 'xas_for_each_marked'
- 'xbc_array_for_each_value'
- 'xbc_for_each_key_value'
- 'xbc_node_for_each_array_value'
- 'xbc_node_for_each_child'
- 'xbc_node_for_each_key_value'
- 'xbc_node_for_each_subkey'
- 'zorro_for_each_dev'
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '.*'
Priority: 1
IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 8
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true
# Taken from git's rules
PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10
PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: false
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp03
TabWidth: 8
UseTab: Always
...

View file

@ -43,7 +43,7 @@
/* VPN interface name matching */ /* VPN interface name matching */
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
static const char * const vpn_prefixes[] = { static const char *const vpn_prefixes[] = {
"tun", "ppp", "tap", "wg", "ipsec", "xfrm", "utun", "l2tp", "gre", "tun", "ppp", "tap", "wg", "ipsec", "xfrm", "utun", "l2tp", "gre",
}; };
@ -55,8 +55,8 @@ static bool is_vpn_ifname(const char *name)
return false; return false;
for (i = 0; i < ARRAY_SIZE(vpn_prefixes); i++) { for (i = 0; i < ARRAY_SIZE(vpn_prefixes); i++) {
if (strncmp(name, vpn_prefixes[i], if (strncmp(name, vpn_prefixes[i], strlen(vpn_prefixes[i])) ==
strlen(vpn_prefixes[i])) == 0) 0)
return true; return true;
} }
if (strstr(name, "vpn") || strstr(name, "VPN")) if (strstr(name, "vpn") || strstr(name, "VPN"))
@ -183,8 +183,7 @@ struct dev_ioctl_data {
struct ifreq *kifr; /* kernel pointer, saved from x2 */ struct ifreq *kifr; /* kernel pointer, saved from x2 */
}; };
static int dev_ioctl_entry(struct kretprobe_instance *ri, static int dev_ioctl_entry(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct dev_ioctl_data *data = (void *)ri->data; struct dev_ioctl_data *data = (void *)ri->data;
@ -197,8 +196,7 @@ static int dev_ioctl_entry(struct kretprobe_instance *ri,
return 0; return 0;
} }
static int dev_ioctl_ret(struct kretprobe_instance *ri, static int dev_ioctl_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct dev_ioctl_data *data = (void *)ri->data; struct dev_ioctl_data *data = (void *)ri->data;
char name[IFNAMSIZ]; char name[IFNAMSIZ];
@ -249,8 +247,7 @@ struct dev_ifconf_data {
bool target; bool target;
}; };
static int dev_ifconf_entry(struct kretprobe_instance *ri, static int dev_ifconf_entry(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct dev_ifconf_data *data = (void *)ri->data; struct dev_ifconf_data *data = (void *)ri->data;
@ -259,8 +256,7 @@ static int dev_ifconf_entry(struct kretprobe_instance *ri,
return 0; return 0;
} }
static int dev_ifconf_ret(struct kretprobe_instance *ri, static int dev_ifconf_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct dev_ifconf_data *data = (void *)ri->data; struct dev_ifconf_data *data = (void *)ri->data;
struct ifconf ifc; struct ifconf ifc;
@ -325,8 +321,7 @@ struct rtnl_fill_data {
bool should_filter; bool should_filter;
}; };
static int rtnl_fill_entry(struct kretprobe_instance *ri, static int rtnl_fill_entry(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct rtnl_fill_data *data = (void *)ri->data; struct rtnl_fill_data *data = (void *)ri->data;
struct net_device *dev; struct net_device *dev;
@ -351,8 +346,7 @@ static int rtnl_fill_entry(struct kretprobe_instance *ri,
return 0; return 0;
} }
static int rtnl_fill_ret(struct kretprobe_instance *ri, static int rtnl_fill_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct rtnl_fill_data *data = (void *)ri->data; struct rtnl_fill_data *data = (void *)ri->data;
@ -393,8 +387,7 @@ struct inet6_fill_data {
bool should_filter; bool should_filter;
}; };
static int inet6_fill_entry(struct kretprobe_instance *ri, static int inet6_fill_entry(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct inet6_fill_data *data = (void *)ri->data; struct inet6_fill_data *data = (void *)ri->data;
struct inet6_ifaddr *ifa; struct inet6_ifaddr *ifa;
@ -422,8 +415,7 @@ static int inet6_fill_entry(struct kretprobe_instance *ri,
return 0; return 0;
} }
static int inet6_fill_ret(struct kretprobe_instance *ri, static int inet6_fill_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct inet6_fill_data *data = (void *)ri->data; struct inet6_fill_data *data = (void *)ri->data;
@ -459,8 +451,7 @@ struct inet_fill_data {
bool should_filter; bool should_filter;
}; };
static int inet_fill_entry(struct kretprobe_instance *ri, static int inet_fill_entry(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct inet_fill_data *data = (void *)ri->data; struct inet_fill_data *data = (void *)ri->data;
struct in_ifaddr *ifa; struct in_ifaddr *ifa;
@ -484,8 +475,7 @@ static int inet_fill_entry(struct kretprobe_instance *ri,
return 0; return 0;
} }
static int inet_fill_ret(struct kretprobe_instance *ri, static int inet_fill_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct inet_fill_data *data = (void *)ri->data; struct inet_fill_data *data = (void *)ri->data;
@ -522,8 +512,7 @@ struct fib_route_data {
bool target; bool target;
}; };
static int fib_route_entry(struct kretprobe_instance *ri, static int fib_route_entry(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct fib_route_data *data = (void *)ri->data; struct fib_route_data *data = (void *)ri->data;
@ -549,8 +538,7 @@ static int fib_route_entry(struct kretprobe_instance *ri,
* synchronously under its own fd context no concurrent access to * synchronously under its own fd context no concurrent access to
* the same seq_file is possible between our entry and return handlers. * the same seq_file is possible between our entry and return handlers.
*/ */
static int fib_route_ret(struct kretprobe_instance *ri, static int fib_route_ret(struct kretprobe_instance *ri, struct pt_regs *regs)
struct pt_regs *regs)
{ {
struct fib_route_data *data = (void *)ri->data; struct fib_route_data *data = (void *)ri->data;
struct seq_file *seq = data->seq; struct seq_file *seq = data->seq;
@ -583,7 +571,8 @@ static int fib_route_ret(struct kretprobe_instance *ri,
/* Extract the interface name (first field, tab-delimited) */ /* Extract the interface name (first field, tab-delimited) */
for (j = 0; j < IFNAMSIZ - 1 && j < (int)line_len && for (j = 0; j < IFNAMSIZ - 1 && j < (int)line_len &&
src[j] != '\t' && src[j] != '\n'; j++) src[j] != '\t' && src[j] != '\n';
j++)
ifname[j] = src[j]; ifname[j] = src[j];
ifname[j] = '\0'; ifname[j] = '\0';
@ -661,8 +650,8 @@ static int __init vpnhide_init(void)
/* 0600: root-only read/write. UIDs are written here by service.sh /* 0600: root-only read/write. UIDs are written here by service.sh
* and WebUI (both root). Apps must not see the target list. */ * and WebUI (both root). Apps must not see the target list. */
targets_entry = proc_create("vpnhide_targets", 0600, NULL, targets_entry =
&targets_proc_ops); proc_create("vpnhide_targets", 0600, NULL, &targets_proc_ops);
pr_info(MODNAME ": loaded — write UIDs to /proc/vpnhide_targets\n"); pr_info(MODNAME ": loaded — write UIDs to /proc/vpnhide_targets\n");
return 0; return 0;

View file

@ -34,14 +34,14 @@ import java.util.concurrent.atomic.AtomicBoolean
* Only "System Framework" needs to be in LSPosed scope. * Only "System Framework" needs to be in LSPosed scope.
*/ */
class HookEntry : IXposedHookLoadPackage { class HookEntry : IXposedHookLoadPackage {
private val hookInstalled = AtomicBoolean(false) private val hookInstalled = AtomicBoolean(false)
override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) { override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam) {
// Only hook system_server. handleLoadPackage fires multiple times // Only hook system_server. handleLoadPackage fires multiple times
// in system_server (once per hosted package / APEX), so we use // in system_server (once per hosted package / APEX), so we use
// compareAndSet to install hooks exactly once. // compareAndSet to install hooks exactly once.
val inSystemServer = hookInstalled.get() || val inSystemServer =
hookInstalled.get() ||
lpparam.processName == "android" || lpparam.processName == "android" ||
android.os.Process.myUid() == 1000 android.os.Process.myUid() == 1000
@ -53,7 +53,10 @@ class HookEntry : IXposedHookLoadPackage {
} }
} }
private inline fun tryHook(name: String, block: () -> Unit) { private inline fun tryHook(
name: String,
block: () -> Unit,
) {
try { try {
block() block()
} catch (t: Throwable) { } catch (t: Throwable) {
@ -85,6 +88,7 @@ class HookEntry : IXposedHookLoadPackage {
// ================================================================== // ==================================================================
@Volatile private var systemServerTargetUids: Set<Int>? = null @Volatile private var systemServerTargetUids: Set<Int>? = null
@Volatile private var targetUidsFileObserver: android.os.FileObserver? = null @Volatile private var targetUidsFileObserver: android.os.FileObserver? = null
private val uidLock = Any() private val uidLock = Any()
@ -146,11 +150,15 @@ class HookEntry : IXposedHookLoadPackage {
private fun watchTargetUidsFile() { private fun watchTargetUidsFile() {
val dir = "/data/system" val dir = "/data/system"
val filename = "vpnhide_uids.txt" val filename = "vpnhide_uids.txt"
val observer = object : android.os.FileObserver( val observer =
object : android.os.FileObserver(
File(dir), File(dir),
CREATE or CLOSE_WRITE or MOVED_TO or MODIFY CREATE or CLOSE_WRITE or MOVED_TO or MODIFY,
) {
override fun onEvent(
event: Int,
path: String?,
) { ) {
override fun onEvent(event: Int, path: String?) {
if (path == filename) { if (path == filename) {
XposedBridge.log("VpnHide: $filename changed (event=$event), invalidating UID cache") XposedBridge.log("VpnHide: $filename changed (event=$event), invalidating UID cache")
systemServerTargetUids = null systemServerTargetUids = null
@ -170,8 +178,10 @@ class HookEntry : IXposedHookLoadPackage {
*/ */
private fun hookNCWriteToParcel() { private fun hookNCWriteToParcel() {
XposedHelpers.findAndHookMethod( XposedHelpers.findAndHookMethod(
NetworkCapabilities::class.java, "writeToParcel", NetworkCapabilities::class.java,
android.os.Parcel::class.java, Integer.TYPE, "writeToParcel",
android.os.Parcel::class.java,
Integer.TYPE,
object : XC_MethodHook() { object : XC_MethodHook() {
private val savedTransport = ThreadLocal<Long>() private val savedTransport = ThreadLocal<Long>()
private val savedCaps = ThreadLocal<Long>() private val savedCaps = ThreadLocal<Long>()
@ -188,7 +198,12 @@ class HookEntry : IXposedHookLoadPackage {
// Read all original values before mutating anything // Read all original values before mutating anything
val caps = XposedHelpers.getLongField(nc, "mNetworkCapabilities") val caps = XposedHelpers.getLongField(nc, "mNetworkCapabilities")
val ti = try { XposedHelpers.getObjectField(nc, "mTransportInfo") } catch (_: Throwable) { null } val ti =
try {
XposedHelpers.getObjectField(nc, "mTransportInfo")
} catch (_: Throwable) {
null
}
// Mutate — if any step fails, restore everything // Mutate — if any step fails, restore everything
try { try {
@ -226,9 +241,10 @@ class HookEntry : IXposedHookLoadPackage {
XposedHelpers.setLongField(nc, "mTransportTypes", origTransport) XposedHelpers.setLongField(nc, "mTransportTypes", origTransport)
if (origCaps != null) XposedHelpers.setLongField(nc, "mNetworkCapabilities", origCaps) if (origCaps != null) XposedHelpers.setLongField(nc, "mNetworkCapabilities", origCaps)
XposedHelpers.setObjectField(nc, "mTransportInfo", origTi) XposedHelpers.setObjectField(nc, "mTransportInfo", origTi)
} catch (_: Throwable) {} } catch (_: Throwable) {
} }
} }
},
) )
XposedBridge.log("VpnHide: hooked NetworkCapabilities.writeToParcel") XposedBridge.log("VpnHide: hooked NetworkCapabilities.writeToParcel")
} }
@ -241,8 +257,10 @@ class HookEntry : IXposedHookLoadPackage {
*/ */
private fun hookNIWriteToParcel() { private fun hookNIWriteToParcel() {
XposedHelpers.findAndHookMethod( XposedHelpers.findAndHookMethod(
NetworkInfo::class.java, "writeToParcel", NetworkInfo::class.java,
android.os.Parcel::class.java, Integer.TYPE, "writeToParcel",
android.os.Parcel::class.java,
Integer.TYPE,
object : XC_MethodHook() { object : XC_MethodHook() {
private val savedType = ThreadLocal<Int>() private val savedType = ThreadLocal<Int>()
@ -265,9 +283,10 @@ class HookEntry : IXposedHookLoadPackage {
savedType.remove() savedType.remove()
try { try {
XposedHelpers.setIntField(param.thisObject, "mNetworkType", origType) XposedHelpers.setIntField(param.thisObject, "mNetworkType", origType)
} catch (_: Throwable) {} } catch (_: Throwable) {
} }
} }
},
) )
XposedBridge.log("VpnHide: hooked NetworkInfo.writeToParcel") XposedBridge.log("VpnHide: hooked NetworkInfo.writeToParcel")
} }
@ -280,8 +299,10 @@ class HookEntry : IXposedHookLoadPackage {
*/ */
private fun hookLPWriteToParcel() { private fun hookLPWriteToParcel() {
XposedHelpers.findAndHookMethod( XposedHelpers.findAndHookMethod(
LinkProperties::class.java, "writeToParcel", LinkProperties::class.java,
android.os.Parcel::class.java, Integer.TYPE, "writeToParcel",
android.os.Parcel::class.java,
Integer.TYPE,
object : XC_MethodHook() { object : XC_MethodHook() {
private val savedIfname = ThreadLocal<String>() private val savedIfname = ThreadLocal<String>()
@ -304,9 +325,10 @@ class HookEntry : IXposedHookLoadPackage {
savedIfname.remove() savedIfname.remove()
try { try {
XposedHelpers.setObjectField(param.thisObject, "mIfaceName", origIfname) XposedHelpers.setObjectField(param.thisObject, "mIfaceName", origIfname)
} catch (_: Throwable) {} } catch (_: Throwable) {
} }
} }
},
) )
XposedBridge.log("VpnHide: hooked LinkProperties.writeToParcel") XposedBridge.log("VpnHide: hooked LinkProperties.writeToParcel")
} }

View file

@ -54,8 +54,8 @@ class MainActivity : ComponentActivity() {
} }
} }
private fun suExec(cmd: String): Pair<Int, String> { private fun suExec(cmd: String): Pair<Int, String> =
return try { try {
val proc = Runtime.getRuntime().exec(arrayOf("su", "-c", cmd)) val proc = Runtime.getRuntime().exec(arrayOf("su", "-c", cmd))
try { try {
// Drain stderr in the background to prevent the process from // Drain stderr in the background to prevent the process from
@ -73,16 +73,15 @@ private fun suExec(cmd: String): Pair<Int, String> {
Log.e(TAG, "su exec failed: ${e.message}") Log.e(TAG, "su exec failed: ${e.message}")
-1 to "" -1 to ""
} }
}
private suspend fun suExecAsync(cmd: String): Pair<Int, String> = private suspend fun suExecAsync(cmd: String): Pair<Int, String> = withContext(Dispatchers.IO) { suExec(cmd) }
withContext(Dispatchers.IO) { suExec(cmd) }
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun VpnHideApp() { fun VpnHideApp() {
val darkTheme = isSystemInDarkTheme() val darkTheme = isSystemInDarkTheme()
val colorScheme = if (android.os.Build.VERSION.SDK_INT >= 31) { val colorScheme =
if (android.os.Build.VERSION.SDK_INT >= 31) {
val context = LocalContext.current val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
} else { } else {
@ -111,22 +110,33 @@ fun VpnHideApp() {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val (_, targetsRaw) = suExec( val (_, targetsRaw) =
"cat $KMOD_TARGETS 2>/dev/null || cat $ZYGISK_TARGETS 2>/dev/null || true" suExec(
"cat $KMOD_TARGETS 2>/dev/null || cat $ZYGISK_TARGETS 2>/dev/null || true",
) )
val selected = targetsRaw.lines() val selected =
targetsRaw
.lines()
.map { it.trim() } .map { it.trim() }
.filter { it.isNotEmpty() && !it.startsWith("#") } .filter { it.isNotEmpty() && !it.startsWith("#") }
.toSet() .toSet()
val installedApps = pm.getInstalledApplications(PackageManager.GET_META_DATA) val installedApps = pm.getInstalledApplications(PackageManager.GET_META_DATA)
val entries = installedApps.map { info -> val entries =
val label = try { installedApps
.map { info ->
val label =
try {
pm.getApplicationLabel(info).toString() pm.getApplicationLabel(info).toString()
} catch (_: Exception) { info.packageName } } catch (_: Exception) {
val icon = try { info.packageName
}
val icon =
try {
pm.getApplicationIcon(info) pm.getApplicationIcon(info)
} catch (_: Exception) { null } } catch (_: Exception) {
null
}
val isSystem = (info.flags and ApplicationInfo.FLAG_SYSTEM) != 0 val isSystem = (info.flags and ApplicationInfo.FLAG_SYSTEM) != 0
AppEntry( AppEntry(
packageName = info.packageName, packageName = info.packageName,
@ -142,7 +152,8 @@ fun VpnHideApp() {
} }
} }
val filteredApps = remember(allApps, searchQuery, showSystem) { val filteredApps =
remember(allApps, searchQuery, showSystem) {
val q = searchQuery.trim().lowercase() val q = searchQuery.trim().lowercase()
allApps.filter { app -> allApps.filter { app ->
(showSystem || !app.isSystem || app.selected) && (showSystem || !app.isSystem || app.selected) &&
@ -157,16 +168,18 @@ fun VpnHideApp() {
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("VPN Hide") }, title = { Text("VPN Hide") },
colors = TopAppBarDefaults.topAppBarColors( colors =
TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer, containerColor = MaterialTheme.colorScheme.primaryContainer,
titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer, titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
) ),
) )
}, },
bottomBar = { bottomBar = {
Surface(tonalElevation = 3.dp) { Surface(tonalElevation = 3.dp) {
Row( Row(
modifier = Modifier modifier =
Modifier
.fillMaxWidth() .fillMaxWidth()
.navigationBarsPadding() .navigationBarsPadding()
.padding(horizontal = 16.dp, vertical = 12.dp), .padding(horizontal = 16.dp, vertical = 12.dp),
@ -189,16 +202,18 @@ fun VpnHideApp() {
} }
} }
} }
} },
) { innerPadding -> ) { innerPadding ->
Column( Column(
modifier = Modifier modifier =
Modifier
.fillMaxSize() .fillMaxSize()
.padding(innerPadding) .padding(innerPadding),
) { ) {
// Search + system toggle // Search + system toggle
Row( Row(
modifier = Modifier modifier =
Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 8.dp), .padding(horizontal = 16.dp, vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
@ -231,11 +246,12 @@ fun VpnHideApp() {
AppRow( AppRow(
app = app, app = app,
onToggle = { onToggle = {
allApps = allApps.map { allApps =
allApps.map {
if (it.packageName == app.packageName) it.copy(selected = !it.selected) else it if (it.packageName == app.packageName) it.copy(selected = !it.selected) else it
} }
dirty = true dirty = true
} },
) )
} }
} }
@ -247,7 +263,8 @@ fun VpnHideApp() {
if (saving) { if (saving) {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
val selected = allApps.filter { it.selected }.map { it.packageName }.sorted() val selected = allApps.filter { it.selected }.map { it.packageName }.sorted()
val body = "# Managed by VPN Hide app\n" + val body =
"# Managed by VPN Hide app\n" +
selected.joinToString("\n") + selected.joinToString("\n") +
if (selected.isNotEmpty()) "\n" else "" if (selected.isNotEmpty()) "\n" else ""
@ -269,7 +286,10 @@ fun VpnHideApp() {
} }
} }
private fun buildSaveCommand(body: String, selectedPackages: List<String>): String { private fun buildSaveCommand(
body: String,
selectedPackages: List<String>,
): String {
val b64 = android.util.Base64.encodeToString(body.toByteArray(), android.util.Base64.NO_WRAP) val b64 = android.util.Base64.encodeToString(body.toByteArray(), android.util.Base64.NO_WRAP)
val parts = mutableListOf<String>() val parts = mutableListOf<String>()
@ -287,7 +307,8 @@ private fun buildSaveCommand(body: String, selectedPackages: List<String>): Stri
// Uses the same approach as kmod/service.sh — real newlines in $UIDS via heredoc-style // Uses the same approach as kmod/service.sh — real newlines in $UIDS via heredoc-style
// accumulation, not printf \n escapes. // accumulation, not printf \n escapes.
if (selectedPackages.isNotEmpty()) { if (selectedPackages.isNotEmpty()) {
val uidResolution = buildString { val uidResolution =
buildString {
append("ALL_PKGS=\"\$(pm list packages -U 2>/dev/null)\"") append("ALL_PKGS=\"\$(pm list packages -U 2>/dev/null)\"")
append("; UIDS=\"\"") append("; UIDS=\"\"")
for (pkg in selectedPackages) { for (pkg in selectedPackages) {
@ -314,9 +335,13 @@ private fun buildSaveCommand(body: String, selectedPackages: List<String>): Stri
} }
@Composable @Composable
private fun AppRow(app: AppEntry, onToggle: () -> Unit) { private fun AppRow(
app: AppEntry,
onToggle: () -> Unit,
) {
Row( Row(
modifier = Modifier modifier =
Modifier
.fillMaxWidth() .fillMaxWidth()
.clickable(onClick = onToggle) .clickable(onClick = onToggle)
.padding(horizontal = 16.dp, vertical = 10.dp), .padding(horizontal = 16.dp, vertical = 10.dp),

View file

@ -43,14 +43,15 @@ private val VPN_PREFIXES = listOf("tun", "wg", "ppp", "tap", "ipsec", "xfrm")
data class CheckResult( data class CheckResult(
val name: String, val name: String,
val passed: Boolean?, // null = informational val passed: Boolean?, // null = informational
val detail: String val detail: String,
) )
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun VpnHideTestApp() { fun VpnHideTestApp() {
val darkTheme = isSystemInDarkTheme() val darkTheme = isSystemInDarkTheme()
val colorScheme = if (android.os.Build.VERSION.SDK_INT >= 31) { val colorScheme =
if (android.os.Build.VERSION.SDK_INT >= 31) {
val context = LocalContext.current val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
} else { } else {
@ -75,18 +76,20 @@ fun VpnHideTestApp() {
topBar = { topBar = {
TopAppBar( TopAppBar(
title = { Text("VPNHide Diagnostics") }, title = { Text("VPNHide Diagnostics") },
colors = TopAppBarDefaults.topAppBarColors( colors =
TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer, containerColor = MaterialTheme.colorScheme.primaryContainer,
titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer, titleContentColor = MaterialTheme.colorScheme.onPrimaryContainer,
),
) )
) },
}
) { innerPadding -> ) { innerPadding ->
Column( Column(
modifier = Modifier modifier =
Modifier
.fillMaxSize() .fillMaxSize()
.padding(innerPadding) .padding(innerPadding)
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp),
) { ) {
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
@ -94,7 +97,7 @@ fun VpnHideTestApp() {
text = summary, text = summary,
style = MaterialTheme.typography.titleMedium, style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier.padding(bottom = 8.dp),
) )
Button( Button(
@ -106,7 +109,7 @@ fun VpnHideTestApp() {
val passed = scored.count { it.passed == true } val passed = scored.count { it.passed == true }
summary = "$passed/${scored.size} passed" summary = "$passed/${scored.size} passed"
}, },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth(),
) { ) {
Text("Run All Checks") Text("Run All Checks")
} }
@ -114,10 +117,11 @@ fun VpnHideTestApp() {
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
Column( Column(
modifier = Modifier modifier =
Modifier
.fillMaxSize() .fillMaxSize()
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(6.dp) verticalArrangement = Arrangement.spacedBy(6.dp),
) { ) {
for (r in results) { for (r in results) {
CheckCard(r) CheckCard(r)
@ -131,21 +135,26 @@ fun VpnHideTestApp() {
@Composable @Composable
fun CheckCard(r: CheckResult) { fun CheckCard(r: CheckResult) {
val containerColor = when (r.passed) { val containerColor =
when (r.passed) {
true -> Color(0xFFE8F5E9) true -> Color(0xFFE8F5E9)
false -> Color(0xFFFFEBEE) false -> Color(0xFFFFEBEE)
null -> MaterialTheme.colorScheme.surfaceVariant null -> MaterialTheme.colorScheme.surfaceVariant
} }
val darkTheme = isSystemInDarkTheme() val darkTheme = isSystemInDarkTheme()
val actualColor = if (darkTheme) { val actualColor =
if (darkTheme) {
when (r.passed) { when (r.passed) {
true -> Color(0xFF1B5E20).copy(alpha = 0.3f) true -> Color(0xFF1B5E20).copy(alpha = 0.3f)
false -> Color(0xFFB71C1C).copy(alpha = 0.3f) false -> Color(0xFFB71C1C).copy(alpha = 0.3f)
null -> MaterialTheme.colorScheme.surfaceVariant null -> MaterialTheme.colorScheme.surfaceVariant
} }
} else containerColor } else {
containerColor
}
val badgeColor = when (r.passed) { val badgeColor =
when (r.passed) {
true -> Color(0xFF2E7D32) true -> Color(0xFF2E7D32)
false -> Color(0xFFC62828) false -> Color(0xFFC62828)
null -> MaterialTheme.colorScheme.onSurfaceVariant null -> MaterialTheme.colorScheme.onSurfaceVariant
@ -154,25 +163,30 @@ fun CheckCard(r: CheckResult) {
Card( Card(
shape = RoundedCornerShape(8.dp), shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = actualColor), colors = CardDefaults.cardColors(containerColor = actualColor),
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth(),
) { ) {
Column(modifier = Modifier.padding(12.dp)) { Column(modifier = Modifier.padding(12.dp)) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( Text(
text = r.name, text = r.name,
style = MaterialTheme.typography.bodyLarge, style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f),
) )
Text( Text(
text = when (r.passed) { true -> "PASS"; false -> "FAIL"; null -> "INFO" }, text =
when (r.passed) {
true -> "PASS"
false -> "FAIL"
null -> "INFO"
},
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 13.sp, fontSize = 13.sp,
color = badgeColor color = badgeColor,
) )
} }
Spacer(Modifier.height(4.dp)) Spacer(Modifier.height(4.dp))
@ -180,7 +194,7 @@ fun CheckCard(r: CheckResult) {
text = r.detail, text = r.detail,
style = MaterialTheme.typography.bodySmall, style = MaterialTheme.typography.bodySmall,
fontFamily = FontFamily.Monospace, fontFamily = FontFamily.Monospace,
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f) color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.8f),
) )
} }
} }
@ -230,8 +244,11 @@ private fun runAllChecks(cm: ConnectivityManager): List<CheckResult> {
return results return results
} }
private fun nativeCheck(name: String, block: () -> String): CheckResult { private fun nativeCheck(
return try { name: String,
block: () -> String,
): CheckResult =
try {
val raw = block() val raw = block()
val passed = raw.startsWith("PASS") val passed = raw.startsWith("PASS")
Log.i(TAG, "[$name] ${if (passed) "PASS" else "FAIL"}: $raw") Log.i(TAG, "[$name] ${if (passed) "PASS" else "FAIL"}: $raw")
@ -241,19 +258,20 @@ private fun nativeCheck(name: String, block: () -> String): CheckResult {
Log.e(TAG, "[$name] $detail", e) Log.e(TAG, "[$name] $detail", e)
CheckResult(name, false, detail) CheckResult(name, false, detail)
} }
}
private fun checkHasTransportVpn(cm: ConnectivityManager): CheckResult { private fun checkHasTransportVpn(cm: ConnectivityManager): CheckResult {
val name = "7. hasTransport(VPN)" val name = "7. hasTransport(VPN)"
Log.i(TAG, "=== CHECK: $name ===") Log.i(TAG, "=== CHECK: $name ===")
val net = cm.activeNetwork val net = cm.activeNetwork
if (net == null) return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") } if (net == null) return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") }
val caps = cm.getNetworkCapabilities(net) val caps =
cm.getNetworkCapabilities(net)
?: return CheckResult(name, true, "PASS: no capabilities").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no capabilities").also { Log.i(TAG, "[$name] ${it.detail}") }
val hasVpn = caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN) val hasVpn = caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
val hasWifi = caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) val hasWifi = caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
val hasCellular = caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) val hasCellular = caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
val detail = if (!hasVpn) { val detail =
if (!hasVpn) {
"PASS: hasTransport(VPN)=false, WIFI=$hasWifi, CELLULAR=$hasCellular" "PASS: hasTransport(VPN)=false, WIFI=$hasWifi, CELLULAR=$hasCellular"
} else { } else {
"FAIL: hasTransport(VPN)=true, WIFI=$hasWifi, CELLULAR=$hasCellular" "FAIL: hasTransport(VPN)=true, WIFI=$hasWifi, CELLULAR=$hasCellular"
@ -266,9 +284,11 @@ private fun checkHasTransportVpn(cm: ConnectivityManager): CheckResult {
private fun checkHasCapabilityNotVpn(cm: ConnectivityManager): CheckResult { private fun checkHasCapabilityNotVpn(cm: ConnectivityManager): CheckResult {
val name = "8. hasCapability(NOT_VPN)" val name = "8. hasCapability(NOT_VPN)"
Log.i(TAG, "=== CHECK: $name ===") Log.i(TAG, "=== CHECK: $name ===")
val net = cm.activeNetwork val net =
cm.activeNetwork
?: return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") }
val caps = cm.getNetworkCapabilities(net) val caps =
cm.getNetworkCapabilities(net)
?: return CheckResult(name, true, "PASS: no capabilities").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no capabilities").also { Log.i(TAG, "[$name] ${it.detail}") }
val notVpn = caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) val notVpn = caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
val detail = if (notVpn) "PASS: NOT_VPN capability present" else "FAIL: NOT_VPN capability MISSING" val detail = if (notVpn) "PASS: NOT_VPN capability present" else "FAIL: NOT_VPN capability MISSING"
@ -279,9 +299,11 @@ private fun checkHasCapabilityNotVpn(cm: ConnectivityManager): CheckResult {
private fun checkTransportInfo(cm: ConnectivityManager): CheckResult { private fun checkTransportInfo(cm: ConnectivityManager): CheckResult {
val name = "9. getTransportInfo()" val name = "9. getTransportInfo()"
Log.i(TAG, "=== CHECK: $name ===") Log.i(TAG, "=== CHECK: $name ===")
val net = cm.activeNetwork val net =
cm.activeNetwork
?: return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") }
val caps = cm.getNetworkCapabilities(net) val caps =
cm.getNetworkCapabilities(net)
?: return CheckResult(name, true, "PASS: no capabilities").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no capabilities").also { Log.i(TAG, "[$name] ${it.detail}") }
val info = caps.transportInfo val info = caps.transportInfo
val className = info?.javaClass?.name ?: "null" val className = info?.javaClass?.name ?: "null"
@ -296,7 +318,8 @@ private fun checkNetworkInterfaceEnum(): CheckResult {
val name = "10. NetworkInterface enum" val name = "10. NetworkInterface enum"
Log.i(TAG, "=== CHECK: $name ===") Log.i(TAG, "=== CHECK: $name ===")
return try { return try {
val ifaces = NetworkInterface.getNetworkInterfaces() val ifaces =
NetworkInterface.getNetworkInterfaces()
?: return CheckResult(name, true, "PASS: returned null").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: returned null").also { Log.i(TAG, "[$name] ${it.detail}") }
val allNames = mutableListOf<String>() val allNames = mutableListOf<String>()
val vpnNames = mutableListOf<String>() val vpnNames = mutableListOf<String>()
@ -305,7 +328,8 @@ private fun checkNetworkInterfaceEnum(): CheckResult {
Log.i(TAG, "[$name] ${iface.name} up=${iface.isUp} loopback=${iface.isLoopback} p2p=${iface.isPointToPoint}") Log.i(TAG, "[$name] ${iface.name} up=${iface.isUp} loopback=${iface.isLoopback} p2p=${iface.isPointToPoint}")
if (VPN_PREFIXES.any { iface.name.startsWith(it) }) vpnNames.add(iface.name) if (VPN_PREFIXES.any { iface.name.startsWith(it) }) vpnNames.add(iface.name)
} }
val detail = if (vpnNames.isEmpty()) { val detail =
if (vpnNames.isEmpty()) {
"PASS: ${allNames.size} ifaces [${allNames.joinToString()}], no VPN" "PASS: ${allNames.size} ifaces [${allNames.joinToString()}], no VPN"
} else { } else {
"FAIL: VPN [${vpnNames.joinToString()}] in [${allNames.joinToString()}]" "FAIL: VPN [${vpnNames.joinToString()}] in [${allNames.joinToString()}]"
@ -341,7 +365,8 @@ private fun checkAllNetworksVpn(cm: ConnectivityManager): CheckResult {
Log.i(TAG, "[$name] Network $net: [${transports.joinToString()}] VPN=$hasVpn") Log.i(TAG, "[$name] Network $net: [${transports.joinToString()}] VPN=$hasVpn")
if (hasVpn) vpnNetworks.add(net.toString()) if (hasVpn) vpnNetworks.add(net.toString())
} }
val detail = if (vpnNetworks.isEmpty()) { val detail =
if (vpnNetworks.isEmpty()) {
"PASS: ${networks.size} networks, none have TRANSPORT_VPN" "PASS: ${networks.size} networks, none have TRANSPORT_VPN"
} else { } else {
"FAIL: ${vpnNetworks.size} network(s) with TRANSPORT_VPN: [${vpnNetworks.joinToString()}]" "FAIL: ${vpnNetworks.size} network(s) with TRANSPORT_VPN: [${vpnNetworks.joinToString()}]"
@ -353,9 +378,11 @@ private fun checkAllNetworksVpn(cm: ConnectivityManager): CheckResult {
private fun checkActiveNetworkVpn(cm: ConnectivityManager): CheckResult { private fun checkActiveNetworkVpn(cm: ConnectivityManager): CheckResult {
val name = "11. ActiveNetwork transports" val name = "11. ActiveNetwork transports"
Log.i(TAG, "=== CHECK: $name ===") Log.i(TAG, "=== CHECK: $name ===")
val net = cm.activeNetwork val net =
cm.activeNetwork
?: return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") }
val caps = cm.getNetworkCapabilities(net) val caps =
cm.getNetworkCapabilities(net)
?: return CheckResult(name, true, "PASS: no capabilities").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no capabilities").also { Log.i(TAG, "[$name] ${it.detail}") }
val transports = mutableListOf<String>() val transports = mutableListOf<String>()
mapOf( mapOf(
@ -367,7 +394,8 @@ private fun checkActiveNetworkVpn(cm: ConnectivityManager): CheckResult {
NetworkCapabilities.TRANSPORT_WIFI_AWARE to "WIFI_AWARE", NetworkCapabilities.TRANSPORT_WIFI_AWARE to "WIFI_AWARE",
).forEach { (id, label) -> if (caps.hasTransport(id)) transports.add(label) } ).forEach { (id, label) -> if (caps.hasTransport(id)) transports.add(label) }
val hasVpn = caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN) val hasVpn = caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
val detail = if (!hasVpn) { val detail =
if (!hasVpn) {
"PASS: transports=[${transports.joinToString()}], no VPN" "PASS: transports=[${transports.joinToString()}], no VPN"
} else { } else {
"FAIL: transports include VPN: [${transports.joinToString()}]" "FAIL: transports include VPN: [${transports.joinToString()}]"
@ -379,9 +407,11 @@ private fun checkActiveNetworkVpn(cm: ConnectivityManager): CheckResult {
private fun checkLinkPropertiesIfname(cm: ConnectivityManager): CheckResult { private fun checkLinkPropertiesIfname(cm: ConnectivityManager): CheckResult {
val name = "12. LinkProperties ifname" val name = "12. LinkProperties ifname"
Log.i(TAG, "=== CHECK: $name ===") Log.i(TAG, "=== CHECK: $name ===")
val net = cm.activeNetwork val net =
cm.activeNetwork
?: return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no active network").also { Log.i(TAG, "[$name] ${it.detail}") }
val lp = cm.getLinkProperties(net) val lp =
cm.getLinkProperties(net)
?: return CheckResult(name, true, "PASS: no link properties").also { Log.i(TAG, "[$name] ${it.detail}") } ?: return CheckResult(name, true, "PASS: no link properties").also { Log.i(TAG, "[$name] ${it.detail}") }
val ifname = lp.interfaceName ?: "(null)" val ifname = lp.interfaceName ?: "(null)"
val routes = lp.routes.map { "${it.destination} via ${it.gateway} dev ${it.`interface`}" } val routes = lp.routes.map { "${it.destination} via ${it.gateway} dev ${it.`interface`}" }
@ -391,7 +421,8 @@ private fun checkLinkPropertiesIfname(cm: ConnectivityManager): CheckResult {
Log.i(TAG, "[$name] dns=${dns.joinToString(", ")}") Log.i(TAG, "[$name] dns=${dns.joinToString(", ")}")
Log.i(TAG, "[$name] httpProxy=${lp.httpProxy}") Log.i(TAG, "[$name] httpProxy=${lp.httpProxy}")
val isVpn = VPN_PREFIXES.any { ifname.startsWith(it) } val isVpn = VPN_PREFIXES.any { ifname.startsWith(it) }
val detail = if (!isVpn) { val detail =
if (!isVpn) {
"PASS: ifname=$ifname, ${routes.size} routes, dns=[${dns.joinToString()}]" "PASS: ifname=$ifname, ${routes.size} routes, dns=[${dns.joinToString()}]"
} else { } else {
"FAIL: ifname=$ifname is a VPN interface" "FAIL: ifname=$ifname is a VPN interface"
@ -409,7 +440,8 @@ private fun checkProxyHost(): CheckResult {
val socksPort = System.getProperty("socksProxyPort") val socksPort = System.getProperty("socksProxyPort")
Log.i(TAG, "[$name] http=$httpHost:$httpPort, socks=$socksHost:$socksPort") Log.i(TAG, "[$name] http=$httpHost:$httpPort, socks=$socksHost:$socksPort")
val hasProxy = !httpHost.isNullOrEmpty() || !socksHost.isNullOrEmpty() val hasProxy = !httpHost.isNullOrEmpty() || !socksHost.isNullOrEmpty()
val detail = if (!hasProxy) { val detail =
if (!hasProxy) {
"PASS: no proxy (http=$httpHost, socks=$socksHost)" "PASS: no proxy (http=$httpHost, socks=$socksHost)"
} else { } else {
"FAIL: proxy found — http=$httpHost:$httpPort, socks=$socksHost:$socksPort" "FAIL: proxy found — http=$httpHost:$httpPort, socks=$socksHost:$socksPort"
@ -432,7 +464,8 @@ private fun checkProcNetRouteJava(): CheckResult {
if (VPN_PREFIXES.any { line!!.startsWith(it) }) vpnLines.add(line!!.take(60)) if (VPN_PREFIXES.any { line!!.startsWith(it) }) vpnLines.add(line!!.take(60))
} }
} }
val detail = if (vpnLines.isEmpty()) { val detail =
if (vpnLines.isEmpty()) {
"PASS: ${allLines.size} lines, no VPN entries" "PASS: ${allLines.size} lines, no VPN entries"
} else { } else {
"FAIL: ${vpnLines.size} VPN lines:\n${vpnLines.joinToString("\n") { " $it" }}" "FAIL: ${vpnLines.size} VPN lines:\n${vpnLines.joinToString("\n") { " $it" }}"

View file

@ -6,18 +6,32 @@ object NativeChecks {
} }
external fun checkIoctlSiocgifflags(): String external fun checkIoctlSiocgifflags(): String
external fun checkIoctlSiocgifconf(): String external fun checkIoctlSiocgifconf(): String
external fun checkGetifaddrs(): String external fun checkGetifaddrs(): String
external fun checkProcNetRoute(): String external fun checkProcNetRoute(): String
external fun checkProcNetIfInet6(): String external fun checkProcNetIfInet6(): String
external fun checkNetlinkGetlink(): String external fun checkNetlinkGetlink(): String
external fun checkNetlinkGetroute(): String external fun checkNetlinkGetroute(): String
external fun checkProcNetIpv6Route(): String external fun checkProcNetIpv6Route(): String
external fun checkProcNetTcp(): String external fun checkProcNetTcp(): String
external fun checkProcNetTcp6(): String external fun checkProcNetTcp6(): String
external fun checkProcNetUdp(): String external fun checkProcNetUdp(): String
external fun checkProcNetUdp6(): String external fun checkProcNetUdp6(): String
external fun checkProcNetDev(): String external fun checkProcNetDev(): String
external fun checkProcNetFibTrie(): String external fun checkProcNetFibTrie(): String
external fun checkSysClassNet(): String external fun checkSysClassNet(): String
} }