OCT 1. 初始化代码仓库

This commit is contained in:
黄昕 2023-10-18 11:15:16 +08:00
parent 45fbdf1284
commit 1dd2cbbfa1
58 changed files with 15773 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@ -0,0 +1,117 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

6
.idea/compiler.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

15
.idea/git_toolbox_prj.xml Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GitToolBoxProjectSettings">
<option name="commitMessageIssueKeyValidationOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
<option name="commitMessageValidationEnabledOverride">
<BoolValueOverride>
<option name="enabled" value="true" />
</BoolValueOverride>
</option>
</component>
</project>

20
.idea/gradle.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -0,0 +1,10 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
<option name="processCode" value="true" />
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
</profile>
</component>

9
.idea/misc.xml Normal file
View File

@ -0,0 +1,9 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

1
app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

48
app/build.gradle.kts Normal file
View File

@ -0,0 +1,48 @@
plugins {
id("com.android.application")
}
android {
namespace = "com.example.sccproxy"
compileSdk = 33
defaultConfig {
applicationId = "com.example.sccproxy"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
externalNativeBuild {
cmake {
path = file("src/main/cpp/CMakeLists.txt")
version = "3.22.1"
}
}
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.8.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
}

21
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@ -0,0 +1,26 @@
package com.example.sccproxy;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.example.sccproxy", appContext.getPackageName());
}
}

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Sccproxy"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -0,0 +1,40 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.
# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("sccproxy")
INCLUDE_DIRECTORIES(include ./)
FILE(GLOB C_HEADS ./include/*.h ./cJSON/cJSON.h)
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
# is preferred for the same purpose.
#
# In order to load a library into your app from Java/Kotlin, you must call
# System.loadLibrary() and pass the name of the library defined here;
# for GameActivity/NativeActivity derived applications, the same library name must be
# used in the AndroidManifest.xml file.
add_library(${CMAKE_PROJECT_NAME} SHARED
# List C/C++ source files with relative paths to this CMakeLists.txt.
native-lib.cpp srcs/ipcalc.cpp srcs/scc-service.cpp srcs/tunnel-proxy.cpp cJSON/cJSON.c ${C_HEADS})
# Specifies libraries CMake should link to your target library. You
# can link libraries from various origins, such as libraries defined in this
# build script, prebuilt third-party libraries, or Android system libraries.
target_link_libraries(${CMAKE_PROJECT_NAME}
# List libraries link to the target library
android
log)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,300 @@
/*
Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef cJSON__h
#define cJSON__h
#ifdef __cplusplus
extern "C"
{
#endif
#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
#define __WINDOWS__
#endif
#ifdef __WINDOWS__
/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options:
CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default)
CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol
For *nix builds that support visibility attribute, you can define similar behavior by
setting default visibility to hidden by adding
-fvisibility=hidden (for gcc)
or
-xldscope=hidden (for sun cc)
to CFLAGS
then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
*/
#define CJSON_CDECL __cdecl
#define CJSON_STDCALL __stdcall
/* export symbols by default, this is necessary for copy pasting the C and header file */
#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_EXPORT_SYMBOLS
#endif
#if defined(CJSON_HIDE_SYMBOLS)
#define CJSON_PUBLIC(type) type CJSON_STDCALL
#elif defined(CJSON_EXPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL
#elif defined(CJSON_IMPORT_SYMBOLS)
#define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL
#endif
#else /* !__WINDOWS__ */
#define CJSON_CDECL
#define CJSON_STDCALL
#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type
#else
#define CJSON_PUBLIC(type) type
#endif
#endif
/* project version */
#define CJSON_VERSION_MAJOR 1
#define CJSON_VERSION_MINOR 7
#define CJSON_VERSION_PATCH 16
#include <stddef.h>
/* cJSON Types: */
#define cJSON_Invalid (0)
#define cJSON_False (1 << 0)
#define cJSON_True (1 << 1)
#define cJSON_NULL (1 << 2)
#define cJSON_Number (1 << 3)
#define cJSON_String (1 << 4)
#define cJSON_Array (1 << 5)
#define cJSON_Object (1 << 6)
#define cJSON_Raw (1 << 7) /* raw json */
#define cJSON_IsReference 256
#define cJSON_StringIsConst 512
/* The cJSON structure: */
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
} cJSON;
typedef struct cJSON_Hooks
{
/* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */
void *(CJSON_CDECL *malloc_fn)(size_t sz);
void (CJSON_CDECL *free_fn)(void *ptr);
} cJSON_Hooks;
typedef int cJSON_bool;
/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them.
* This is to prevent stack overflows. */
#ifndef CJSON_NESTING_LIMIT
#define CJSON_NESTING_LIMIT 1000
#endif
/* returns the version of cJSON as a string */
CJSON_PUBLIC(const char*) cJSON_Version(void);
/* Supply malloc, realloc and free functions to cJSON */
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */
/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length);
/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
/* Render a cJSON entity to text for transfer/storage. */
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
/* Render a cJSON entity to text for transfer/storage without any formatting. */
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
/* Delete a cJSON entity and all subentities. */
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);
/* Returns the number of items in an array (or object). */
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
/* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);
/* Get item "string" from object. Case insensitive. */
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
/* Check item type and return its value */
CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item);
CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item);
/* These functions check the type of an item */
CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
/* These calls create a cJSON item of the appropriate type. */
CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
/* raw json */
CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
/* Create a string where valuestring references a string so
* it will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
/* Create an object/array that only references it's elements so
* they will not be freed by cJSON_Delete */
CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items.
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
/* Append item to the specified array/object. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
* WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
* writing to `item->string` */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
/* Remove/Detach items from Arrays/Objects. */
CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string);
/* Update array items. */
CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem);
/* Duplicate a cJSON item */
CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
* need to be released. With recurse!=0, it will duplicate any children connected to the item.
* The item->next and ->prev pointers are always zero on return from Duplicate. */
/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal.
* case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */
CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive);
/* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings.
* The input pointer json cannot point to a read-only address area, such as a string constant,
* but should point to a readable and writable address area. */
CJSON_PUBLIC(void) cJSON_Minify(char *json);
/* Helper functions for creating and adding items to an object at the same time.
* They return the added item or NULL on failure. */
CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw);
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
/* When assigning an integer value, it needs to be propagated to valuedouble too. */
#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
/* helper for the cJSON_SetNumberValue macro */
CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
/* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */
CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring);
/* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/
#define cJSON_SetBoolValue(object, boolValue) ( \
(object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \
(object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \
cJSON_Invalid\
)
/* Macro for iterating over an array or object */
#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */
CJSON_PUBLIC(void *) cJSON_malloc(size_t size);
CJSON_PUBLIC(void) cJSON_free(void *object);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2016 Red Hat, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Nikos Mavrogiannopoulos <nmav@redhat.com>
*/
#pragma once
#include "sccproxy.h"
/**
* @brief IPv4
*/
typedef struct {
unsigned int prefix; ///< 网络前缀
char hostip[MAX_IPV4_LEN]; ///< IP 地址
char ip[MAX_IPV4_LEN]; ///< IP 地址
char network[MAX_IPV4_LEN]; ///< 网络地址
char broadcast[MAX_IPV4_LEN]; ///< 网络广播地址
char netmask[MAX_IPV4_LEN]; ///< 网络子网掩码
char hosts[64]; ///< number of hosts in text
char hostmin[MAX_IPV4_LEN]; ///< 最小网络主机 IP
char hostmax[MAX_IPV4_LEN]; ///< 最大网络主机 IP
} IP_INFO, *PIP_INFO;
/**
* @brief IPv4
* @param[in] pIpStr IPv4
* @param[in] pNetmask IPv4子网掩码
* @param[out] pInfo
* @return 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int get_ipv4_info_from_cidr(const char *pIpStr, const char *pNetmask, PIP_INFO pInfo);
/**
* @brief IPv4
* @param[in] pIpStr IPv4 '/' CIDR以及子网掩码 example: 192.168.1.32/24, 192.168.1.32/255.255.255.0
* @param[out] pInfo
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int get_ipv4_info_from_netmask(const char *pIpStr, PIP_INFO pInfo);
/**
* @brief IP// IP
* @param[in] host /
* @param[out] pInfo
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int get_ipv4_info_from_hostname(const char *host, PIP_INFO pInfo);

View File

@ -0,0 +1,8 @@
//
// Created by HuangXin on 2023/10/12.
//
#pragma once
#include <android/log.h>
#define ANDROID_LOG(level, tag, format, args...) (__android_log_print(level, tag, "[%s(%d)] %s:" format, basename(__FILE__), __LINE__, __FUNCTION__, ##args))

View File

@ -0,0 +1,83 @@
//
// Created by HuangXin on 2023/10/12.
//
#pragma once
#define MAX_PATH (256)
/**
* @brief IP (IPv6)
*/
#define MAX_IPV4_LEN (48)
/**
* @brief IP
*/
#define MIN_IPV4_LEN (7)
/**
* @brief SCG ID
*
*/
typedef enum {
WG_TUNNEL_SCG_ID = 3, ///< 隧道服务
WG_CTRL_SCG_ID = 4 ///< 隧道控制服务
} SCG_SVR_ID;
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SCG
* @param[in] pSCGIpAddr SCG IP//
* @param[in] scgPort SCG
* @return 0: 0 @see USER_ERRNO
*/
int init_scgproxy_service(const char *pSCGIpAddr, int scgPort);
/**
* @brief
* @param[in] vmId VMID
* @return 0: 0 @see USER_ERRNO
*/
int remote_tunnel_service_start(int vmId);
/**
* @brief
* @return 0: 0 @see USER_ERRNO
*/
int remote_tunnel_service_stop();
/**
* @brief
* @param[in] pCliPubKey
* @param[in] pCliNetwork
* @param[in] pCliTunNetwork
* @param[out] pSvrNetwork
* @return 0: 0 @see USER_ERRNO
*/
int remote_tunnel_set_params(const char *pCliPubKey, const char *pCliNetwork, const char *pCliTunNetwork, char *pSvrNetwork);
/**
* @brief Wireguard UDP
* @return 0 >0 UDP
*/
unsigned short get_tunnel_proxy_port();
/**
* @brief wireguard UDP
*/
void stop_wireguard_proxy_server();
/**
* @brief wireguard UDP
* @param[out] pPorxyPort UDP 使 IP 127.0.0.1
* @return 0: 0 @see USER_ERRNO
*/
int create_wireguard_proxy_server(unsigned short *pPorxyPort);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,8 @@
//
// Created by HuangXin on 2023/10/13.
//
#pragma once
int get_scg_cur_vmid();
const char *get_scg_proxy_ipaddr();
unsigned short get_scg_proxy_port();

View File

@ -0,0 +1,75 @@
#pragma once
/**
* @brief SDK
*/
enum USER_ERRNO {
ERR_SUCCESS = 0, ///< 成功
ERR_INPUT_PARAMS, ///< 输入参数错误
ERR_UN_SUPPORT, ///< 不支持的操作
ERR_CALL_SHELL, ///< 调用Shell命令失败
ERR_ITEM_EXISTS, ///< 该内容已经存在
ERR_ITEM_UNEXISTS, ///< 该内容不存在
ERR_SYS_INIT, ///< 系统中断
ERR_SYS_CALL, ///< 系统调用
ERR_LOAD_LIBRARY, ///< 加载系统库失败
ERR_MAP_LIBRARY, ///< 加载系统库接口失败
ERR_SYS_TIMEOUT, ///< 系统超时
ERR_SYSTEM_UNINITIALIZE, ///< 系统未初始化
ERR_CREATE_FILE, ///< 创建文件/目录失败
ERR_OPEN_FILE, ///< 打开文件失败
ERR_READ_FILE, ///< 读取文件失败
ERR_WRITE_FILE, ///< 写入文件失败
ERR_FILE_NOT_EXISTS, ///< 文件不存在
ERR_FILE_LOCKED, ///< 文件被锁定
ERR_GET_FILE_SIZE, ///< 获取文件大小失败
ERR_FIND_FILE, ///< 查找文件失败
ERR_COPY_FILE, ///< 复制文件失败
ERR_OPEN_SCM, ///< 打开服务管理器设备失败
ERR_OPEN_SERVICE, ///< 打开服务失败
ERR_CREATE_SERVICE, ///< 创建服务失败
ERR_START_SERVICE, ///< 启动服务失败
ERR_STOP_SERVICE, ///< 停止服务失败
ERR_DELETE_SERVICE, ///< 删除服务失败
ERR_CONFIG_SERVICE, ///< 修改服务配置失败
ERR_GET_SERVICESSTATUS, ///< 获取服务状态失败
ERR_MALLOC_MEMORY, ///< 分配内存失败
ERR_MMAP_MEMORY, ///< 共享内存失败
ERR_MEMORY_STR, ///< 字符串操作失败
ERR_CREATE_PROCESS, ///< 创建进程失败
ERR_PROCESS_RETURN, ///< 进程调用返回失败
ERR_CREATE_THREAD, ///< 创建线程失败
ERR_CREATE_TIMER, ///< 创建定时器失败
ERR_DELETE_TIMER, ///< 销毁定时器失败
ERR_SOCKET_CREATE, ///< 创建 SOCKET 失败
ERR_SOCKET_BIND, ///< 绑定 SOCKET 端口失败
ERR_SOCKET_CONNECT, ///< 连接 TCP SOCKET 服务器失败
ERR_SOCKET_LISTEN, ///< TCP SOCKET 服务监听失败
ERR_SOCKET_BIND_PORT, ///< 绑定端口失败
ERR_SOCKET_SET_OPT, ///< 设置 SOCKET 参数失败
ERR_SOCKET_GET_OPT, ///< 读取 SOCKET 参数失败
ERR_BCRYPT_OPEN = 100, ///< 创建加密算法失败
ERR_BCRYPT_GETPROPERTY, ///< 获取加密算法属性失败
ERR_BCRYPT_CREATEHASH, ///< 创建 Hash 算法失败
ERR_BCRYPT_HASHDATA, ///< 计算 Hash 数据失败
ERR_BCRYPT_FINISHHASH, ///< 计算 Hash 结果失败
ERR_NET_UNCONNECT = 200, ///< 网络未连接
ERR_NET_CATEGORY_MODE, ///< 网络工作模式
ERR_NET_INTELNEL_ICS, ///< 共享 Intelnet 网络 ICS 共享失败
ERR_NET_WIREGUARD_ICS, ///< 共享 WireGuard 网络 ICS 共享失败
ERR_GET_IPFOWARDTBL = 300, ///< 获取系统 IP 转发表失败
ERR_CREATE_COMMOBJECT = 400, ///< 创建 COM 对象失败
ERR_CALL_COMMOBJECT, ///< 调用 COM 对象失败
ERR_WMI_GET_COMMOBJECT, ///< 获取 WMI COM 对象失败
ERR_WMI_CONN_SVR, ///< 连接到 WMI 失败
ERR_WMI_SET_PROXY, ///< 设置 WMI 代理服务失败
ERR_WMI_QUERY, ///< 执行 WMI SQL查询失败
ERR_WMI_EXEC_METHOD, ///< 执行 WMI 函数失败
ERR_COM_INITIALIZE, ///< 初始化COM失败
ERR_JSON_CREATE = 500, ///< 创建 JSON 对象失败
ERR_JSON_DECODE, ///< 从 JSON 反序列化对象失败
ERR_HTTP_SERVER_RSP = 600, ///< HTTP 服务端返回错误
ERR_HTTP_POST_DATA, ///< 发送 POST 请求失败
ERR_NET_ADD_ROUTE, ///< 添加路由失败
ERR_NET_REMOVE_ROUTE, ///< 删除路由失败
};

View File

@ -0,0 +1,140 @@
#include <jni.h>
#include <string>
#include <unistd.h>
#include "sccproxy.h"
#include "log.h"
#include "usrerr.h"
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_sccproxy_MainActivity_stringFromJNI(
JNIEnv *env,
jobject /* this */) {
int ret;
int vmId = 123;
char svrTunnelNetwork[256];
unsigned short tunnelProxyPort = 0;
std::string hello = "Hello from C++";
//-----------------------------------------------------------------------
// 系统初始化, 程序启动时调用一次
//-----------------------------------------------------------------------
// Init step 1. 初始化 SCG 代理服务
ret = init_scgproxy_service("127.0.0.1", 10800);
if (ret == ERR_SUCCESS) {
ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "init_scgproxy_service: SUCCESSED\n");
} else {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "init_scgproxy_service error: %d\n", ret);
goto error;
}
// Init step 2. 初始化 SCG 代理服务
// 初始化 wireguard 隧道代理服务,如果成功会返回代理端口, 程序启动时调用一次
// 填入 Wiregurad 配置文件 Endpoint 参数为 Endpoint = 127.0.0.1:tunnelProxyPort
ret = create_wireguard_proxy_server(&tunnelProxyPort);
if (ret == ERR_SUCCESS) {
ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "create_wireguard_proxy_server: SUCCESSED, proxyPort = %d\n", tunnelProxyPort);
} else {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "create_wireguard_proxy_server error: %d\n", ret);
goto error;
}
//-----------------------------------------------------------------------
// 隧道控制,每次启动/停止 SCC 服务时调用
//-----------------------------------------------------------------------
// SCC Service Step 1. 客户端获取隧道配置并连接到虚拟机后,首先要对虚拟机里面的隧道进行配置
/**
{
"code": "00000",
"data": {
"cliHost": "10.10.10.1/24", // TODO Set to pCliTunNetwork(Step 1) & et to wireguard 配置文件 Address=/AllowedIPs= (Step 2)
"cliPubKey": "fcosdnZe7PQjkjpFNNZUxv9Dtl36XubAj6d6cDU6R34=", // TODO Set to pCliPubKey(Step 1)
"cliPriKey": "6PIYlZHVDzRbgvfWgeu27OfO0NeN8WrFBMAa56hIL0M=", // TODO Set to wireguard 配置文件 PrivateKey= (Step 2)
"vmInfoList": [
{
"svrPubKey": "nssKUB0d+uRLiys/YzCqA0n8xhw6fuRgs2Q5asEAExc=", // TODO Set to wireguard 配置文件 PublicKey= (Step 2)
"vmName": "ct-pool-95-1696922439711",
"vmId": 827, // TODO Set to vmid (Step 3)
"extVmId": "a3adc00b-d794-46b7-bb83-1951f3368cfb",
"vmNetwork": "172.31.18.108/24",
"scgIp": "112.17.28.220",
"scgPort": 1080,
"portMapIp": "112.17.28.221",
"portMapPort": 2002
}
]
},
"message": "操作成功"
}
*/
ret = remote_tunnel_set_params("fcosdnZe7PQjkjpFNNZUxv9Dtl36XubAj6d6cDU6R34=", "192.168.100.0/24", "10.10.10.0/24", svrTunnelNetwork);
if (ret == ERR_SUCCESS) {
ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "remote_tunnel_set_params: SUCCESSED, Server Tunnel Network: %s\n", svrTunnelNetwork);
} else {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "remote_tunnel_set_params error: %d\n", ret);
goto error;
}
// SCC Service Step 2. 创建本地 Wireguard 配置文件
// TODO
/**
[Interface]
PrivateKey = 6PIYlZHVDzRbgvfWgeu27OfO0NeN8WrFBMAa56hIL0M= // TODO from (step 1)
Address = 10.10.10.1/24 // TODO from (step 1)
[Peer]
PublicKey = nssKUB0d+uRLiys/YzCqA0n8xhw6fuRgs2Q5asEAExc= // TODO from (step 1)
AllowedIPs = 10.10.10.0/24,172.31.18.0/24 // TODO from (Step 1 pCliTunNetwork and svrTunnelNetwork)
Endpoint = 127.0.0.1:49301 // TODO Port from tunnelProxyPort (Init Step 2)
PersistentKeepalive = 30 // TODO fixed or configure by user
*/
// SCC Service Step 3. 启动虚拟机内服务端隧道
ret = remote_tunnel_service_start(vmId);
if (ret == ERR_SUCCESS) {
ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "remote_tunnel_service_start: SUCCESSED, Current Connect VMID: %d\n", vmId);
} else {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "remote_tunnel_service_start error: %d\n", ret);
goto error;
}
// SCC Service Step 4. 启动客户端本地 Wireguard 隧道
// TODO
// SCC Service Step 5. 配置客户端 iptables 规则,启动 SCC 内网转发
// TODO
// SCC Service Step 6. 端口虚拟机,停止服务端隧道
ret = remote_tunnel_service_stop();
if (ret == ERR_SUCCESS) {
ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "remote_tunnel_service_stop: SUCCESSED, Current Connect VMID: %d\n", vmId);
} else {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "remote_tunnel_service_stop error: %d\n", ret);
goto error;
}
// SCC Service Step 7. 删除客户端 iptables 规则, 停止 SCC 内网转发
// TODO
// SCC Service Step 8. 停止本地 Wireguard 隧道
// TODO
//-----------------------------------------------------------------------
// 资源清理,程序退出时调用
//-----------------------------------------------------------------------
// UnInit step 1. 停止虚拟机内隧道服务程序
// remote_tunnel_service_stop
// UnInit step 2. 删除客户端 iptables 规则, 停止 SCC 内网转发
// TODO
// UnInit step 3. 停止本地 Wireguard 隧道
// TODO
// UnInit step 4. 停止客户端 Wireguard 隧道 UDP 代理服务
stop_wireguard_proxy_server();
error:
return env->NewStringUTF(hello.c_str());
}

View File

@ -0,0 +1,511 @@
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <cstring>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include "usrerr.h"
#include "ipcalc.h"
#include "log.h"
static const char *p2_table(unsigned pow) {
static const char *pow2[] = {
"1",
"2",
"4",
"8",
"16",
"32",
"64",
"128",
"256",
"512",
"1024",
"2048",
"4096",
"8192",
"16384",
"32768",
"65536",
"131072",
"262144",
"524288",
"1048576",
"2097152",
"4194304",
"8388608",
"16777216",
"33554432",
"67108864",
"134217728",
"268435456",
"536870912",
"1073741824",
"2147483648",
"4294967296",
"8589934592",
"17179869184",
"34359738368",
"68719476736",
"137438953472",
"274877906944",
"549755813888",
"1099511627776",
"2199023255552",
"4398046511104",
"8796093022208",
"17592186044416",
"35184372088832",
"70368744177664",
"140737488355328",
"281474976710656",
"562949953421312",
"1125899906842624",
"2251799813685248",
"4503599627370496",
"9007199254740992",
"18014398509481984",
"36028797018963968",
"72057594037927936",
"144115188075855872",
"288230376151711744",
"576460752303423488",
"1152921504606846976",
"2305843009213693952",
"4611686018427387904",
"9223372036854775808",
"18446744073709551616",
"36893488147419103232",
"73786976294838206464",
"147573952589676412928",
"295147905179352825856",
"590295810358705651712",
"1180591620717411303424",
"2361183241434822606848",
"4722366482869645213696",
"9444732965739290427392",
"18889465931478580854784",
"37778931862957161709568",
"75557863725914323419136",
"151115727451828646838272",
"302231454903657293676544",
"604462909807314587353088",
"1208925819614629174706176",
"2417851639229258349412352",
"4835703278458516698824704",
"9671406556917033397649408",
"19342813113834066795298816",
"38685626227668133590597632",
"77371252455336267181195264",
"154742504910672534362390528",
"309485009821345068724781056",
"618970019642690137449562112",
"1237940039285380274899124224",
"2475880078570760549798248448",
"4951760157141521099596496896",
"9903520314283042199192993792",
"19807040628566084398385987584",
"39614081257132168796771975168",
"79228162514264337593543950336",
"158456325028528675187087900672",
"316912650057057350374175801344",
"633825300114114700748351602688",
"1267650600228229401496703205376",
"2535301200456458802993406410752",
"5070602400912917605986812821504",
"10141204801825835211973625643008",
"20282409603651670423947251286016",
"40564819207303340847894502572032",
"81129638414606681695789005144064",
"162259276829213363391578010288128",
"324518553658426726783156020576256",
"649037107316853453566312041152512",
"1298074214633706907132624082305024",
"2596148429267413814265248164610048",
"5192296858534827628530496329220096",
"10384593717069655257060992658440192",
"20769187434139310514121985316880384",
"41538374868278621028243970633760768",
"83076749736557242056487941267521536",
"166153499473114484112975882535043072",
"332306998946228968225951765070086144",
"664613997892457936451903530140172288",
"1329227995784915872903807060280344576",
"2658455991569831745807614120560689152",
"5316911983139663491615228241121378304",
"10633823966279326983230456482242756608",
"21267647932558653966460912964485513216",
"42535295865117307932921825928971026432",
"85070591730234615865843651857942052864",
"170141183460469231731687303715884105728",
};
if (pow <= 127) {
return pow2[pow];
}
return "";
}
static int bit_count(unsigned int i) {
int c = 0;
unsigned int seen_one = 0;
while (i > 0) {
if (i & 1) {
seen_one = 1;
c++;
} else {
if (seen_one) {
return -1;
}
}
i >>= 1;
}
return c;
}
/**
* @brief creates a netmask from a specified number of bits
* This function converts a prefix length to a netmask. As CIDR (classless
* internet domain internet domain routing) has taken off, more an more IP
* addresses are being specified in the format address/prefix
* (i.e. 192.168.2.3/24, with a corresponding netmask 255.255.255.0). If you
* need to see what netmask corresponds to the prefix part of the address, this
* is the function. See also @ref mask2prefix.
* @param prefix prefix is the number of bits to create a mask for.
* @return a network mask, in network byte order.
*/
unsigned int prefix2mask(int prefix) {
if (prefix) {
return htonl(~((1 << (32 - prefix)) - 1));
} else {
return htonl(0);
}
}
/**
* @brief calculates the number of bits masked off by a netmask.
* This function calculates the significant bits in an IP address as specified by
* a netmask. See also @ref prefix2mask.
* @param mask is the netmask, specified as an struct in_addr in network byte order.
* @return the number of significant bits.
*/
static int mask2prefix(struct in_addr mask) {
return bit_count(ntohl(mask.s_addr));
}
static int ipv4_mask_to_int(const char *prefix) {
int ret;
struct in_addr in = {};
ret = inet_pton(AF_INET, prefix, &in);
if (ret == 0)
return -1;
return mask2prefix(in);
}
/**
* @brief calculate broadcast address given an IP address and a prefix length.
* @param addr an IP address in network byte order.
* @param prefix a prefix length.
* @return the calculated broadcast address for the network, in network byte order.
*/
static struct in_addr calc_broadcast(struct in_addr addr, int prefix) {
struct in_addr mask = {};
struct in_addr broadcast = {};
mask.s_addr = prefix2mask(prefix);
memset(&broadcast, 0, sizeof(broadcast));
broadcast.s_addr = (addr.s_addr & mask.s_addr) | ~mask.s_addr;
return broadcast;
}
/**
* @brief calculates the network address for a specified address and prefix.
* @param addr an IP address, in network byte order
* @param prefix the network prefix
* @return the base address of the network that addr is associated with, in
* network byte order.
*/
static struct in_addr calc_network(struct in_addr addr, int prefix) {
struct in_addr mask = {};
struct in_addr network = {};
mask.s_addr = prefix2mask(prefix);
memset(&network, 0, sizeof(network));
network.s_addr = addr.s_addr & mask.s_addr;
return network;
}
char *ipv4_prefix_to_hosts(char *hosts, unsigned hosts_size, unsigned prefix) {
unsigned tmp;
if (prefix >= 31) {
snprintf(hosts, hosts_size, "%s", p2_table(32 - prefix));
} else {
tmp = (1 << (32 - prefix)) - 2;
snprintf(hosts, hosts_size, "%u", tmp);
}
return hosts;
}
static int str_to_prefix(int *ipv6, const char *prefixStr) {
int prefix;
if (!(*ipv6) && strchr(prefixStr, '.')) { /* prefix is 255.x.x.x */
prefix = ipv4_mask_to_int(prefixStr);
} else {
prefix = strtol(prefixStr, nullptr, 10);
}
if (prefix > 32 && !(*ipv6)) {
*ipv6 = 1;
}
if (prefix < 0 || (((*ipv6) && prefix > 128) || (!(*ipv6) && prefix > 32))) {
return -1;
}
return prefix;
}
static int get_ipv4_info(const char *pIpStr, int prefix, PIP_INFO pInfo) {
struct in_addr ip = {}, netmask = {}, network = {}, broadcast = {}, minhost = {}, maxhost = {};
char namebuf[INET_ADDRSTRLEN + 1];
char *ipStr = strdup(pIpStr);
memset(pInfo, 0, sizeof(*pInfo));
if (inet_pton(AF_INET, ipStr, &ip) <= 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Bad IPv4 address: %s\n", ipStr);
free(ipStr);
return -ERR_UN_SUPPORT;
}
/* Handle CIDR entries such as 172/8 */
if (prefix >= 0) {
auto tmp = const_cast<char *>(ipStr);
int i;
for (i = 3; i > 0; i--) {
tmp = strchr(tmp, '.');
if (!tmp) {
break;
} else {
tmp++;
}
}
tmp = nullptr;
for (; i > 0; i--) {
if (asprintf(&tmp, "%s.0", ipStr) == -1) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Memory allocation failure\n");
free(ipStr);
return -ERR_MALLOC_MEMORY;
}
ipStr = tmp;
}
} else { // assume good old days classful Internet
prefix = 32;
}
if (prefix > 32) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Bad IPv4 prefix: %d\n", prefix);
free(ipStr);
return -ERR_UN_SUPPORT;
}
if (inet_ntop(AF_INET, &ip, namebuf, sizeof(namebuf)) == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Error calculating the IPv4 network\n");
free(ipStr);
return -ERR_UN_SUPPORT;
}
strncpy(pInfo->ip, namebuf, MAX_IPV4_LEN);
netmask.s_addr = prefix2mask(prefix);
memset(namebuf, '\0', sizeof(namebuf));
if (inet_ntop(AF_INET, &netmask, namebuf, INET_ADDRSTRLEN) == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "inet_ntop error\n");
free(ipStr);
return -ERR_UN_SUPPORT;
}
strncpy(pInfo->netmask, namebuf, MAX_IPV4_LEN);
pInfo->prefix = prefix;
broadcast = calc_broadcast(ip, prefix);
memset(namebuf, '\0', sizeof(namebuf));
if (inet_ntop(AF_INET, &broadcast, namebuf, INET_ADDRSTRLEN) == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "inet_ntop error\n");
free(ipStr);
return -ERR_UN_SUPPORT;
}
strncpy(pInfo->broadcast, namebuf, MAX_IPV4_LEN);
network = calc_network(ip, prefix);
memset(namebuf, '\0', sizeof(namebuf));
if (inet_ntop(AF_INET, &network, namebuf, INET_ADDRSTRLEN) == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "inet_ntop error\n");
free(ipStr);
return -ERR_UN_SUPPORT;
}
strncpy(pInfo->network, namebuf, MAX_IPV4_LEN);
if (prefix < 32) {
memcpy(&minhost, &network, sizeof(minhost));
if (prefix <= 30) {
minhost.s_addr = htonl(ntohl(minhost.s_addr) | 1);
}
if (inet_ntop(AF_INET, &minhost, namebuf, INET_ADDRSTRLEN) == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "inet_ntop error\n");
free(ipStr);
return -ERR_UN_SUPPORT;
}
strncpy(pInfo->hostmin, namebuf, MAX_IPV4_LEN);
memcpy(&maxhost, &network, sizeof(minhost));
maxhost.s_addr |= ~netmask.s_addr;
if (prefix <= 30) {
maxhost.s_addr = htonl(ntohl(maxhost.s_addr) - 1);
}
if (inet_ntop(AF_INET, &maxhost, namebuf, sizeof(namebuf)) == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Error calculating the IPv4 network\n");
free(ipStr);
return -ERR_UN_SUPPORT;
}
strncpy(pInfo->hostmax, namebuf, MAX_IPV4_LEN);
} else {
strncpy(pInfo->hostmin, pInfo->network, MAX_IPV4_LEN);
strncpy(pInfo->hostmax, pInfo->network, MAX_IPV4_LEN);
}
ipv4_prefix_to_hosts(pInfo->hosts, sizeof(pInfo->hosts), prefix);
free(ipStr);
return ERR_SUCCESS;
}
/**
* @brief IPv4
* @param[in] pIpStr IPv4 '/' CIDR以及子网掩码 example: 192.168.1.32/24, 192.168.1.32/255.255.255.0
* @param[out] pInfo
* @return 0: 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int get_ipv4_info_from_cidr(const char *pIpStr, PIP_INFO pInfo) {
int ret, prefix;
char *prefixStr;
int familyIPv6 = 0;
char *ipStr = strdup(pIpStr);
if (pIpStr == nullptr || strlen(pIpStr) < MIN_IPV4_LEN || strlen(pIpStr) >= MAX_IPV4_LEN) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Input pIpStr format error: %s\n", pIpStr);
return -ERR_INPUT_PARAMS;
}
if (pInfo == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Input pInfo is NULL\n");
return -ERR_INPUT_PARAMS;
}
if (strchr(ipStr, '/') != nullptr) {
prefixStr = static_cast<char *>(strchr(ipStr, '/'));
*prefixStr = '\0'; /* fix up ipStr */
prefixStr++;
} else {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Input pIpStr isn't CIDR format: %s\n", pIpStr);
free(ipStr);
return -ERR_INPUT_PARAMS;
}
if (strchr(prefixStr, '.') != nullptr) {
prefix = ipv4_mask_to_int(prefixStr);
} else {
prefix = str_to_prefix(&familyIPv6, prefixStr);
}
ret = get_ipv4_info(ipStr, prefix, pInfo);
free(ipStr);
return ret;
}
/**
* @brief IPv4
* @param[in] pIpStr IPv4
* @param[in] pNetmask IPv4子网掩码
* @param[out] pInfo
* @return 0 @see USER_ERRNO
* - -ERR_INPUT_PARAMS
* - -ERR_UN_SUPPORT
* - -ERR_MALLOC_MEMORY
* - ERR_SUCCESS
*/
int get_ipv4_info_from_netmask(const char *pIpStr, const char *pNetmask, PIP_INFO pInfo) {
int prefix;
if (pIpStr == nullptr || strlen(pIpStr) < MIN_IPV4_LEN || strlen(pIpStr) >= MAX_IPV4_LEN) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Input pIpStr format error: %s\n", pIpStr);
return -ERR_INPUT_PARAMS;
}
if (pNetmask == nullptr || strlen(pNetmask) < MIN_IPV4_LEN || strlen(pNetmask) >= MAX_IPV4_LEN) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Input pNetmask format error: %s\n", pNetmask);
return -ERR_INPUT_PARAMS;
}
if (pInfo == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "IPCALC", "Input pInfo is NULL.\n");
return -ERR_INPUT_PARAMS;
}
prefix = ipv4_mask_to_int(pNetmask);
return get_ipv4_info(pIpStr, prefix, pInfo);
}
int get_ipv4_info_from_hostname(const char *host, PIP_INFO pInfo) {
struct addrinfo *res, *rp;
struct addrinfo hints = {};
int err;
static char ipname[64];
void *addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
err = getaddrinfo(host, nullptr, &hints, &res);
if (err != 0) {
return -ERR_INPUT_PARAMS;
}
for (rp = res; rp != nullptr; rp = rp->ai_next) {
if (rp->ai_family == AF_INET) {
addr = (&reinterpret_cast<sockaddr_in * >(rp->ai_addr)->sin_addr);
} else {
addr = (&reinterpret_cast<sockaddr_in6 * >(rp->ai_addr)->sin6_addr);
}
if (inet_ntop(rp->ai_family, addr, ipname, sizeof(ipname)) != nullptr) {
freeaddrinfo(res);
strncpy(pInfo->hostip, ipname, MAX_IPV4_LEN);
return ERR_SUCCESS;
}
}
freeaddrinfo(res);
return ERR_ITEM_EXISTS;
}

View File

@ -0,0 +1,376 @@
#include "usrerr.h"
#include "httplib.h"
#include "log.h"
#include "sccproxy.h"
#include "ipcalc.h"
#include "scg-service.h"
#include "../cJSON/cJSON.h"
#define SET_CLIENTCFG_PATH ("/tunnel/setconfig")
#define SET_CLIENTSTART_TUNNEL ("/tunnel/start")
typedef struct {
char scgProxyIpAddr[MAX_PATH];
int scgProxyPort;
int curConnVmId;
int isEnable;
httplib::Client *g_tunCtrlCtx;
} SCGPROXY_CONFIG, *PSCGPROXY_CONFIG;
static SCGPROXY_CONFIG g_scgProxyCfg;
int get_scg_cur_vmid() {
return g_scgProxyCfg.curConnVmId;
}
const char *get_scg_proxy_ipaddr() {
return g_scgProxyCfg.scgProxyIpAddr;
}
unsigned short get_scg_proxy_port() {
return static_cast<unsigned short>(g_scgProxyCfg.scgProxyPort);
}
/**
* @brief SCG
* @param[in] pSCGIpAddr SCG IP//
* @param[in] scgPort SCG
* @return 0 @see USER_ERRNO
*/
int init_scgproxy_service(const char *pSCGIpAddr, int scgPort) {
IP_INFO ipInfo;
int ret;
char scgProxyUrl[MAX_PATH * 4];
memset(&g_scgProxyCfg, 0, sizeof(SCGPROXY_CONFIG));
if (pSCGIpAddr == nullptr || strlen(pSCGIpAddr) == 0 || strlen(pSCGIpAddr) >= MAX_IPV4_LEN) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input pSCGIpAddr params error: %s\n", pSCGIpAddr ? pSCGIpAddr : "NULL String");
return -ERR_INPUT_PARAMS;
}
if (scgPort <= 0 || scgPort > 65535) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input scgPort params error: %d\n", scgPort);
return -ERR_INPUT_PARAMS;
}
ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "Enable SCG Proxy: %s:%d, Tunnel Control VMID = %d, Tunnel Data VMID = %d \n",
pSCGIpAddr, scgPort, WG_CTRL_SCG_ID, WG_TUNNEL_SCG_ID);
if ((ret = get_ipv4_info_from_hostname(pSCGIpAddr, &ipInfo)) != ERR_SUCCESS) {
ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "get_ipv4_info_from_hostname error: %d\n", ret);
return ret;
}
strncpy(g_scgProxyCfg.scgProxyIpAddr, ipInfo.hostip, MAX_PATH);
g_scgProxyCfg.scgProxyPort = scgPort;
memset(scgProxyUrl, 0, MAX_PATH * 4);
snprintf(scgProxyUrl, MAX_PATH * 4 - 1, "http://%s:%d", g_scgProxyCfg.scgProxyIpAddr, g_scgProxyCfg.scgProxyPort);
g_scgProxyCfg.g_tunCtrlCtx = new httplib::Client(scgProxyUrl);
if (g_scgProxyCfg.g_tunCtrlCtx == nullptr) {
ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "Create HTTP Proxy error: %s\n", scgProxyUrl);
return -ERR_SYSTEM_UNINITIALIZE;
} else {
g_scgProxyCfg.g_tunCtrlCtx->set_connection_timeout(0, 1000000); // 1 second
g_scgProxyCfg.g_tunCtrlCtx->set_read_timeout(5, 0); // 5 seconds
g_scgProxyCfg.g_tunCtrlCtx->set_write_timeout(5, 0); // 5 seconds
g_scgProxyCfg.g_tunCtrlCtx->set_keep_alive(true);
g_scgProxyCfg.g_tunCtrlCtx->set_post_connect_cb([](socket_t sock) {
int ret;
unsigned char vmid[4];
unsigned char *p;
const unsigned int id = htonl(g_scgProxyCfg.curConnVmId);
const auto svrId = static_cast<unsigned char>(WG_CTRL_SCG_ID);
unsigned char scgProxy[] = {0x01, // VERSION
0x09, // Length
0xF0, // ++++++ INFO[0] TYPE
0x04, // INFO[0] LENGTH
0, // INFO[0] VMID[0]
0, // INFO[0] VMID[1]
0, // INFO[0] VMID[2]
0, // INFO[0] VMID[3]
0xF1, // INFO[1] TYPE
0x01, // INFO[1] LENGTH
svrId}; // ------ INFO[1] SCG Service ID
p = scgProxy;
memcpy(vmid, &id, 4);
scgProxy[4] = vmid[0];
scgProxy[5] = vmid[1];
scgProxy[6] = vmid[2];
scgProxy[7] = vmid[3];
ret = send(sock, reinterpret_cast<const char *>(p), sizeof(scgProxy), 0);
if (ret != sizeof(scgProxy)) {
ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "Service Connected To SCG Server(vmid = %d, SCGAppId = %d) error: %d\n",
g_scgProxyCfg.curConnVmId, WG_CTRL_SCG_ID, ret);
}
ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "Service Connected To SCG Server:vmid = %d, SCGAppId = %d: %d\n",
g_scgProxyCfg.curConnVmId, WG_CTRL_SCG_ID, sock);
});
}
g_scgProxyCfg.isEnable = true;
return ERR_SUCCESS;
}
static int remote_tunnel_service_control(int vmId, bool start) {
if (vmId < 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input pSCGIpAddr params error: %d\n", vmId);
return -ERR_INPUT_PARAMS;
}
if (!g_scgProxyCfg.isEnable) {
ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "SCG Proxy Service Uninit.\n");
return -ERR_SYSTEM_UNINITIALIZE;
}
if (g_scgProxyCfg.g_tunCtrlCtx == nullptr) {
ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "Server Control Service don't connected(g_tunnelHttpCtx is not initialize).");
return -ERR_SYSTEM_UNINITIALIZE;
} else {
char *pJsonString;
cJSON *pRoot;
cJSON *pMsgContent;
cJSON *rspCode;
httplib::Result res;
g_scgProxyCfg.curConnVmId = vmId;
pRoot = cJSON_CreateObject();
if (pRoot == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Create JSON Error.\n");
return -ERR_JSON_CREATE;
}
cJSON_AddNumberToObject(pRoot, "ver", 1);
cJSON_AddNumberToObject(pRoot, "cryptoType", 0);
cJSON_AddNumberToObject(pRoot, "timeStamp", time(nullptr));
pMsgContent = cJSON_CreateObject();
if (pMsgContent == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Create JSON Error.\n");
cJSON_Delete(pRoot);
return -ERR_JSON_CREATE;
}
cJSON_AddItemToObject(pRoot, "msgContent", pMsgContent);
cJSON_AddBoolToObject(pMsgContent, "isStart", start);
pJsonString = cJSON_PrintUnformatted(pRoot);
cJSON_Delete(pRoot);
res = g_scgProxyCfg.g_tunCtrlCtx->Post(SET_CLIENTSTART_TUNNEL, pJsonString, "application/json");
if (res.error() != httplib::Error::Success) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s error: %s\n", SET_CLIENTSTART_TUNNEL, pJsonString,
httplib::to_string(res.error()).c_str());
free(pJsonString);
return -ERR_HTTP_POST_DATA;
}
if (res->status != 200) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s server return HTTP error: %d\n", SET_CLIENTSTART_TUNNEL,
pJsonString,
res->status);
free(pJsonString);
return -ERR_HTTP_SERVER_RSP;
}
ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "+++++ Http Request %s\n---- Http Response %s\n", pJsonString, res->body.c_str());
free(pJsonString);
if (strlen(res->body.c_str()) == 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Server response empty message.\n");
return -ERR_READ_FILE;
}
pRoot = cJSON_Parse(res->body.c_str());
if (pRoot == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode JSON %s Error.\n", res->body.c_str());
return -ERR_JSON_DECODE;
}
pMsgContent = cJSON_GetObjectItem(pRoot, "msgContent");
if (pMsgContent == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent) JSON %s Error.\n", res->body.c_str());
cJSON_Delete(pRoot);
return -ERR_JSON_DECODE;
}
rspCode = cJSON_GetObjectItem(pMsgContent, "errCode");
if (rspCode == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.rspCode) JSON %s Error.\n", res->body.c_str());
cJSON_Delete(pRoot);
return -ERR_JSON_DECODE;
}
cJSON_Delete(pRoot);
return rspCode->valueint;
}
}
/**
* @brief
* @return 0: 0 @see USER_ERRNO
*/
int remote_tunnel_service_stop() {
return remote_tunnel_service_control(g_scgProxyCfg.curConnVmId, false);
}
/**
* @brief
* @param[in] vmId VMID
* @return 0: 0 @see USER_ERRNO
*/
int remote_tunnel_service_start(int vmId) {
return remote_tunnel_service_control(vmId, true);
}
/**
* @brief
* @param[in] pCliPubKey
* @param[in] pCliNetwork
* @param[in] pCliTunNetwork
* @param[out] pSvrNetwork
* @return 0: 0 @see USER_ERRNO
*/
int remote_tunnel_set_params(const char *pCliPubKey, const char *pCliNetwork, const char *pCliTunNetwork, char *pSvrNetwork) {
char *pJsonString;
cJSON *pRoot;
cJSON *pMsgContent;
cJSON *pRspCode;
cJSON *pSvrNet;
httplib::Result res;
if (pCliPubKey == nullptr || strlen(pCliPubKey) == 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input pCliPubKey params error: %s\n", pCliPubKey ? pCliPubKey : "NULL String");
return -ERR_INPUT_PARAMS;
}
if (pCliNetwork == nullptr || strlen(pCliNetwork) == 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input pCliNetwork params error: %s\n", pCliNetwork ? pCliNetwork : "NULL String");
return -ERR_INPUT_PARAMS;
}
if (pCliTunNetwork == nullptr || strlen(pCliTunNetwork) == 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input pCliTunNetwork params error: %s\n", pCliTunNetwork ? pCliTunNetwork : "NULL String");
return -ERR_INPUT_PARAMS;
}
if (pSvrNetwork == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Input pSvrNetwork params is null\n");
}
if (g_scgProxyCfg.curConnVmId <= 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Current Unconnect VM, vmid: %d\n", g_scgProxyCfg.curConnVmId);
return -ERR_INPUT_PARAMS;
}
if (!g_scgProxyCfg.isEnable) {
ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "SCG Proxy Service Uninit.\n");
return -ERR_SYSTEM_UNINITIALIZE;
}
pRoot = cJSON_CreateObject();
if (pRoot == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Create JSON Error.\n");
return -ERR_JSON_CREATE;
}
cJSON_AddNumberToObject(pRoot, "ver", 1);
cJSON_AddNumberToObject(pRoot, "cryptoType", 0);
cJSON_AddNumberToObject(pRoot, "timeStamp", time(nullptr));
pMsgContent = cJSON_CreateObject();
if (pMsgContent == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Create JSON Error.\n");
cJSON_Delete(pRoot);
return -ERR_JSON_CREATE;
}
cJSON_AddItemToObject(pRoot, "msgContent", pMsgContent);
cJSON_AddStringToObject(pMsgContent, "cliPublicKey", pCliPubKey);
cJSON_AddStringToObject(pMsgContent, "pCliNetwork", pCliNetwork);
cJSON_AddStringToObject(pMsgContent, "cliTunnelAddr", pCliTunNetwork);
pJsonString = cJSON_PrintUnformatted(pRoot);
cJSON_Delete(pRoot);
res = g_scgProxyCfg.g_tunCtrlCtx->Post(SET_CLIENTCFG_PATH, pJsonString, "application/json");
if (res.error() != httplib::Error::Success) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s error: %s\n", SET_CLIENTCFG_PATH, pJsonString,
httplib::to_string(res.error()).c_str());
free(pJsonString);
return -ERR_HTTP_POST_DATA;
}
if (res->status != 200) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "[%s]:Post Data %s server return HTTP error: %d\n", SET_CLIENTCFG_PATH,
pJsonString,
res->status);
free(pJsonString);
return -ERR_HTTP_SERVER_RSP;
}
ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "+++++ Http Request %s\n---- Http Response %s\n", pJsonString, res->body.c_str());
free(pJsonString);
if (strlen(res->body.c_str()) == 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Server response empty message.\n");
return -ERR_READ_FILE;
}
pRoot = cJSON_Parse(res->body.c_str());
if (pRoot == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode JSON %s Error.\n", res->body.c_str());
return -ERR_JSON_DECODE;
}
pMsgContent = cJSON_GetObjectItem(pRoot, "msgContent");
if (pMsgContent == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent) JSON %s Error.\n", res->body.c_str());
cJSON_Delete(pRoot);
return -ERR_JSON_DECODE;
}
pRspCode = cJSON_GetObjectItem(pMsgContent, "errCode");
if (pRspCode == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.pRspCode) JSON %s Error.\n", res->body.c_str());
cJSON_Delete(pRoot);
return -ERR_JSON_DECODE;
}
if (pRspCode->valueint != 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Server Response Error: %d\n", pRspCode->valueint);
cJSON_Delete(pRoot);
return -ERR_JSON_DECODE;
}
pSvrNet = cJSON_GetObjectItem(pMsgContent, "svrNetwork");
if (pSvrNet == nullptr) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Decode(msgContent.pSvrNet) JSON %s Error.\n", res->body.c_str());
cJSON_Delete(pRoot);
return -ERR_JSON_DECODE;
}
strcpy(pSvrNetwork, pSvrNet->valuestring);
cJSON_Delete(pRoot);
return ERR_SUCCESS;
}

View File

@ -0,0 +1,282 @@
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <cerrno>
#include <csignal>
#include "usrerr.h"
#include "sccproxy.h"
#include "scg-service.h"
#include "log.h"
#ifndef UNUSED
#define UNUSED(x) UNUSED_##x __attribute__((__unused__))
#endif
#define SCG_UDP_HEAD_SIZE (11)
#define SIG_CANCEL_SIGNAL SIGUSR1
typedef struct {
unsigned short targetPort;
unsigned short proxyPort;
int udpProxySock;
int scgGwSock;
pthread_t hProxyTunnelThread;
pthread_t hProxySCGThread;
bool exitNow;
} SCG_PROXY_INFO, *PSCG_PROXY_INFO;
static SCG_PROXY_INFO g_scgProxyInfo;
static int pthread_setcancelstate() {
sigset_t newState, old;
int ret;
sigemptyset(&newState);
sigaddset(&newState, SIG_CANCEL_SIGNAL);
ret = pthread_sigmask(SIG_BLOCK, &newState, &old);
return ret;
}
/**
* Wireguard UDP
* @return 0 >0 UDP
*/
unsigned short get_tunnel_proxy_port() {
return g_scgProxyInfo.proxyPort;
}
/**
* @brief wireguard UDP
*/
void stop_wireguard_proxy_server() {
PSCG_PROXY_INFO pProxy = &g_scgProxyInfo;
pProxy->exitNow = true;
if (pProxy->hProxyTunnelThread) {
pthread_kill(pProxy->hProxyTunnelThread, SIG_CANCEL_SIGNAL);
ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "Proxy Tunnel Thread finished(%ld)...... \n",
pProxy->hProxyTunnelThread);
pProxy->hProxyTunnelThread = 0;
close(pProxy->udpProxySock);
}
if (pProxy->hProxySCGThread) {
pthread_kill(pProxy->hProxySCGThread, SIG_CANCEL_SIGNAL);
ANDROID_LOG(ANDROID_LOG_INFO, "SCGPROXY", "Proxy SCG Thread finished(%ld)...... \n", pProxy->hProxySCGThread);
pProxy->hProxySCGThread = 0;
close(pProxy->scgGwSock);
}
}
static void *UDPProxvRemoteThread(void *lpParameter) {
const auto pPeerSock = static_cast<sockaddr_in *>(lpParameter);
PSCG_PROXY_INFO pProxy = &g_scgProxyInfo;
while (pPeerSock && !pProxy->exitNow) {
sockaddr_in remoteWgAddr{};
char ipAddr[MAX_IPV4_LEN];
int addrSize = sizeof(struct sockaddr);
char recvBuf[1500];
int iRecvBytes;
// 代理服务 In
iRecvBytes = recvfrom(pProxy->scgGwSock,
recvBuf,
1500,
0,
reinterpret_cast<struct sockaddr *>(&remoteWgAddr),
reinterpret_cast<socklen_t *>(&addrSize));
memset(ipAddr, 0, MAX_IPV4_LEN);
inet_ntop(AF_INET, &remoteWgAddr.sin_addr.s_addr, ipAddr, MAX_IPV4_LEN);
if (iRecvBytes != -1) {
int sendBytes = sendto(pProxy->udpProxySock,
recvBuf,
iRecvBytes,
0,
reinterpret_cast<struct sockaddr *>(pPeerSock),
sizeof(struct sockaddr));
if (sendBytes != iRecvBytes) {
ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "Porxy Send Data Error(%d): %d/%d\n", errno, sendBytes, iRecvBytes);
}
} else {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", ">>> Scoket In %d Recv %d bytes from %s:%d error %d\n", iRecvBytes,
pProxy->scgGwSock,
ipAddr,
ntohs(remoteWgAddr.sin_port),
errno);
}
usleep(1000);
}
pthread_detach(pthread_self());
pthread_exit(nullptr);
}
static void *UDPProxyRecvThread(void *UNUSED(lpParameter)) {
bool isRemoteInit = false;
sockaddr_in localWgAddr{};
sockaddr_in scgAddr{};
unsigned char recvBuf[1500 + SCG_UDP_HEAD_SIZE];
PSCG_PROXY_INFO pProxy = &g_scgProxyInfo;
char *pRecBuf = reinterpret_cast<char *>(&recvBuf[SCG_UDP_HEAD_SIZE]);
scgAddr.sin_family = AF_INET;
scgAddr.sin_port = htons(get_scg_proxy_port());
inet_pton(AF_INET, get_scg_proxy_ipaddr(), &scgAddr.sin_addr.s_addr);
// 构建 SCG UDP 包头
recvBuf[0] = 0x01; // VERSION
recvBuf[1] = 0x09; // Length
recvBuf[2] = 0xF0; // ++++++ INFO[0] TYPE
recvBuf[3] = 0x04; // INFO[0] LENGTH
recvBuf[4] = 0; // INFO[0] VMID[0]
recvBuf[5] = 0; // INFO[0] VMID[1]
recvBuf[6] = 0; // INFO[0] VMID[2]
recvBuf[7] = 0; // INFO[0] VMID[3]
recvBuf[8] = 0xF1; // INFO[1] TYPE
recvBuf[9] = 0x01; // INFO[1] LENGTH
recvBuf[10] = WG_TUNNEL_SCG_ID; // ------ INFO[1] SCG Service ID
pProxy->exitNow = false;
while (!pProxy->exitNow) {
char ipAddr[MAX_IPV4_LEN];
int addrSize = sizeof(struct sockaddr);
int iRecvBytes;
// 代理服务 Out
iRecvBytes = recvfrom(pProxy->udpProxySock,
pRecBuf,
1500,
0,
reinterpret_cast<struct sockaddr *>(&localWgAddr),
reinterpret_cast<socklen_t *>(&addrSize));
inet_ntop(AF_INET, &localWgAddr.sin_addr.s_addr, ipAddr, MAX_IPV4_LEN);
if (iRecvBytes != -1) {
int sendBytes;
const unsigned int id = htonl(get_scg_cur_vmid());
unsigned char vmid[4];
memcpy(vmid, &id, 4);
if (!isRemoteInit) {
int ret;
isRemoteInit = true;
if ((ret = pthread_create(&pProxy->hProxySCGThread, nullptr, UDPProxvRemoteThread, &localWgAddr)) != 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Create Thread failed with error(%d): %d\n", errno, ret);
close(pProxy->udpProxySock);
close(pProxy->scgGwSock);
pProxy->exitNow = true;
pthread_detach(pthread_self());
pthread_exit(nullptr);
}
}
recvBuf[4] = vmid[0]; // INFO[0] VMID[0]
recvBuf[5] = vmid[1]; // INFO[0] VMID[1]
recvBuf[6] = vmid[2]; // INFO[0] VMID[2]
recvBuf[7] = vmid[3]; // INFO[0] VMID[3]
// 增加SCG包头数据长度
iRecvBytes += 11;
sendBytes = sendto(pProxy->scgGwSock,
reinterpret_cast<char *>(recvBuf),
iRecvBytes,
0,
reinterpret_cast<struct sockaddr *>(&scgAddr),
sizeof(struct sockaddr));
if (sendBytes != iRecvBytes) {
ANDROID_LOG(ANDROID_LOG_WARN, "SCGPROXY", "Porxy Send Data Error(%d): %d/%d\n", errno, sendBytes, iRecvBytes);
}
}
usleep(1000);
}
pthread_detach(pthread_self());
pthread_exit(nullptr);
}
/**
* @brief wireguard UDP
* @param[out] pPorxyPort UDP 使 IP 127.0.0.1
* @return 0: 0 @see USER_ERRNO
*/
int create_wireguard_proxy_server(unsigned short *pPorxyPort) {
int ret;
int addrSize = sizeof(struct sockaddr_in);
struct sockaddr_in server = {};
struct sockaddr_in bindAddr = {};
int sock;
PSCG_PROXY_INFO pProxy = &g_scgProxyInfo;
pthread_setcancelstate();
memset(&g_scgProxyInfo, 0, sizeof(SCG_PROXY_INFO));
// 创建本地 SOCKET 代理服务器
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Create UDP Socket failed with error: %d\n", errno);
return -ERR_SOCKET_CREATE;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = htonl(INADDR_ANY);
server.sin_port = htons(0);
if (bind(sock, reinterpret_cast<struct sockaddr *>(&server), sizeof(struct sockaddr_in)) == -1) {
close(sock);
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Bind local UDP Socket failed with error: %d\n", errno);
return -ERR_SOCKET_BIND;
}
if ((ret = getsockname(sock, reinterpret_cast<struct sockaddr *>(&bindAddr), reinterpret_cast<socklen_t *>(&addrSize))) != 0) {
close(sock);
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Get UDP Socket bind port failed with error(%d): %d\n", errno, ret);
return -ERR_SOCKET_BIND;
}
// 保存 UDP 代理服务器信息
pProxy->udpProxySock = sock;
pProxy->proxyPort = ntohs(bindAddr.sin_port);
if (pPorxyPort) {
*pPorxyPort = pProxy->proxyPort;
}
ANDROID_LOG(ANDROID_LOG_DEBUG, "SCGPROXY", "Proxy Server socket {%d} bind {%d} port\n", sock, pProxy->proxyPort);
// 创建SCG SOCKET 连接客户端服务
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Create UDP Socket failed with error: %d\n", errno);
close(pProxy->udpProxySock);
return -ERR_SOCKET_CREATE;
}
pProxy->scgGwSock = sock;
// 创建代理服务发送线程
if ((ret = pthread_create(&pProxy->hProxyTunnelThread, nullptr, UDPProxyRecvThread, nullptr)) != 0) {
ANDROID_LOG(ANDROID_LOG_ERROR, "SCGPROXY", "Create Thread failed with error(%d) : %d\n", errno, ret);
close(pProxy->udpProxySock);
close(pProxy->scgGwSock);
return -ERR_CREATE_THREAD;
}
return ERR_SUCCESS;
}

View File

@ -0,0 +1,36 @@
package com.example.sccproxy;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
import com.example.sccproxy.databinding.ActivityMainBinding;
public class MainActivity extends AppCompatActivity {
// Used to load the 'sccproxy' library on application startup.
static {
System.loadLibrary("sccproxy");
}
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
// Example of a call to a native method
TextView tv = binding.sampleText;
tv.setText(stringFromJNI());
}
/**
* A native method that is implemented by the 'sccproxy' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
}

View File

@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/sample_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Sccproxy" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/black</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_200</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">sccproxy</string>
</resources>

View File

@ -0,0 +1,16 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.Sccproxy" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>
<item name="colorOnPrimary">@color/white</item>
<!-- Secondary brand color. -->
<item name="colorSecondary">@color/teal_200</item>
<item name="colorSecondaryVariant">@color/teal_700</item>
<item name="colorOnSecondary">@color/black</item>
<!-- Status bar color. -->
<item name="android:statusBarColor">?attr/colorPrimaryVariant</item>
<!-- Customize your theme here. -->
</style>
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

View File

@ -0,0 +1,17 @@
package com.example.sccproxy;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

4
build.gradle.kts Normal file
View File

@ -0,0 +1,4 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.2" apply false
}

21
gradle.properties Normal file
View File

@ -0,0 +1,21 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Thu Oct 12 09:37:52 CST 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
gradlew vendored Normal file
View File

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
gradlew.bat vendored Normal file
View File

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

17
settings.gradle.kts Normal file
View File

@ -0,0 +1,17 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "sccproxy"
include(":app")