Skip to content

Commit a13d833

Browse files
committed
Add new config support for geoip split routing
1 parent c335fd6 commit a13d833

7 files changed

Lines changed: 159 additions & 24 deletions

YtFlowApp/NewProfilePage.cpp

Lines changed: 121 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,24 @@ namespace winrt::YtFlowApp::implementation
4848
co_return;
4949
}
5050

51+
if (m_selectedSplitRoutingType != L"all")
52+
{
53+
if (SelectedRulesetNameText().Text() == L"")
54+
{
55+
SelectRulesetButton_Click(nullptr, nullptr);
56+
co_return;
57+
}
58+
}
59+
5160
SaveButton().IsEnabled(false);
5261
const auto lifetime{get_strong()};
5362
bool nameDuplicated{false};
5463
NewProfileConfig config;
64+
config.InboundMode = InboundModeButtons().SelectedItem().as<RadioButton>().Tag().as<hstring>();
5565
config.OutboundType = m_selectedOutboundType;
66+
config.SplitRoutingMode = m_selectedSplitRoutingType;
67+
config.SplitRoutingRuleset = SelectedRulesetNameText().Text();
68+
config.RuleResolver = RuleResolverComboBox().SelectedItem().as<ComboBoxItem>().Tag().as<hstring>();
5669

5770
co_await resume_background();
5871

@@ -162,7 +175,7 @@ namespace winrt::YtFlowApp::implementation
162175
" \"plugin\": \"ip-stack\","
163176
" \"plugin_version\": 0,"
164177
" \"param\": {"
165-
" \"tcp_next\": \"fakeip-dns-server.tcp_map_back.main-forward.tcp\","
178+
" \"tcp_next\": \"fakeip-dns-server.tcp_map_back.geoip-dispatcher.tcp\","
166179
" \"udp_next\": \"dns-dispatcher.udp\","
167180
" \"tun\": \"uwp-vpn-tun.tun\""
168181
" }"
@@ -194,8 +207,8 @@ namespace winrt::YtFlowApp::implementation
194207
" \"web_proxy\": null"
195208
" }"
196209
" },"
197-
" \"main-forward\": {"
198-
" \"desc\": \"Forward connections to the main outbound.\","
210+
" \"proxy-forward\": {"
211+
" \"desc\": \"Forward connections to the proxy outbound.\","
199212
" \"plugin\": \"forward\","
200213
" \"plugin_version\": 0,"
201214
" \"param\": {"
@@ -204,6 +217,16 @@ namespace winrt::YtFlowApp::implementation
204217
" \"udp_next\": \"phy.udp\""
205218
" }"
206219
" },"
220+
" \"direct-forward\": {"
221+
" \"desc\": \"Forward connections to the physical outbound.\","
222+
" \"plugin\": \"forward\","
223+
" \"plugin_version\": 0,"
224+
" \"param\": {"
225+
" \"request_timeout\": 200,"
226+
" \"tcp_next\": \"phy.tcp\","
227+
" \"udp_next\": \"phy.udp\""
228+
" }"
229+
" },"
207230
" \"outbound\": {"
208231
" \"desc\": \"Allows runtime selection of outbound proxies from the Library.\","
209232
" \"plugin\": \"dyn-outbound\","
@@ -334,13 +357,26 @@ namespace winrt::YtFlowApp::implementation
334357
" \"prefix_v6\": [38, 12, 32, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]"
335358
" }"
336359
" },"
360+
" \"doh-resolver\": {"
361+
" \"desc\": \"Resolves real IP addresses from a secure, trusted provider.\","
362+
" \"plugin\": \"host-resolver\","
363+
" \"plugin_version\": 0,"
364+
" \"param\": {"
365+
" \"udp\": [],"
366+
" \"tcp\": [],"
367+
" \"doh\": [{"
368+
" \"url\": \"https://1.1.1.1/dns-query\","
369+
" \"next\": \"general-tls.tcp\""
370+
" }]"
371+
" }"
372+
" },"
337373
" \"dns-dispatcher\": {"
338374
" \"desc\": \"Dispatches DNS requests to our DNS server.\","
339375
" \"plugin\": \"simple-dispatcher\","
340376
" \"plugin_version\": 0,"
341377
" \"param\": {"
342-
" \"fallback_tcp\": \"main-forward.tcp\","
343-
" \"fallback_udp\": \"fakeip-dns-server.udp_map_back.main-forward.udp\","
378+
" \"fallback_tcp\": \"reject.tcp\","
379+
" \"fallback_udp\": \"fakeip-dns-server.udp_map_back.geoip-dispatcher.udp\","
344380
" \"rules\": ["
345381
" {"
346382
" \"src\": {"
@@ -357,37 +393,111 @@ namespace winrt::YtFlowApp::implementation
357393
" ]"
358394
" }"
359395
" },"
396+
" \"geoip-dispatcher\": {"
397+
" \"desc\": \"Split routing by GeoIP rules.\","
398+
" \"plugin\": \"rule-dispatcher\","
399+
" \"plugin_version\": 0,"
400+
" \"param\": {"
401+
" \"resolver\": \"doh-resolver.resolver\","
402+
" \"source\": \"dreamacro-geoip\","
403+
" \"actions\": {"
404+
" \"direct\": {"
405+
" \"tcp\": \"direct-forward.tcp\","
406+
" \"udp\": \"direct-forward.udp\""
407+
" },"
408+
" \"proxy\": {"
409+
" \"tcp\": \"proxy-forward.tcp\","
410+
" \"udp\": \"proxy-forward.udp\""
411+
" }"
412+
" },"
413+
" \"rules\": {"
414+
" \"cn\": \"direct\""
415+
" },"
416+
" \"fallback\": {"
417+
" \"tcp\": \"proxy-forward.tcp\","
418+
" \"udp\": \"proxy-forward.udp\""
419+
" }"
420+
" }"
421+
" },"
422+
" \"general-tls\": {"
423+
" \"desc\": \"TLS client stream for h2, DoH etc.\","
424+
" \"plugin\": \"tls-client\","
425+
" \"plugin_version\": 0,"
426+
" \"param\": {"
427+
" \"next\": \"phy.tcp\","
428+
" \"skip_cert_check\": false"
429+
" }"
430+
" },"
360431
" \"fakeip-dns-server\": {"
361432
" \"desc\": \"Respond to DNS request messages using results from the FakeIP resolver.\","
362433
" \"plugin\": \"dns-server\","
363434
" \"plugin_version\": 0,"
364435
" \"param\": {"
365436
" \"concurrency_limit\": 64,"
366437
" \"resolver\": \"fake-ip.resolver\","
367-
" \"tcp_map_back\": [\"main-forward.tcp\"],"
368-
" \"udp_map_back\": [\"main-forward.udp\"],"
438+
" \"tcp_map_back\": [\"proxy-forward.tcp\"],"
439+
" \"udp_map_back\": [\"proxy-forward.udp\"],"
369440
" \"ttl\": 60"
370441
" }"
371442
" }"
372443
"}"_json};
373444

445+
if (config.InboundMode == L"full")
446+
{
447+
doc["uwp-vpn-tun"]["param"]["ipv4_route"] = {"0.0.0.0/1", "128.0.0.0/1"};
448+
doc["uwp-vpn-tun"]["param"]["ipv6_route"] = {"::/1", "8000::/1"};
449+
}
450+
451+
std::string_view ruleResolver = "phy.resolver";
452+
if (config.RuleResolver == L"1111")
453+
{
454+
ruleResolver = "doh-resolver.resolver";
455+
}
456+
else if (config.RuleResolver == L"ali")
457+
{
458+
doc["doh-resolver"]["param"]["doh"][0]["url"] = "https://223.5.5.5/dns-query";
459+
ruleResolver = "doh-resolver.resolver";
460+
}
461+
doc["geoip-dispatcher"]["param"]["resolver"] = ruleResolver;
462+
463+
if (config.SplitRoutingMode == L"all")
464+
{
465+
doc["entry-ip-stack"]["param"]["tcp_next"] = "fakeip-dns-server.tcp_map_back.proxy-forward.tcp";
466+
doc["dns-dispatcher"]["param"]["fallback_udp"] = "fakeip-dns-server.udp_map_back.proxy-forward.udp";
467+
doc.erase("direct-forward");
468+
}
469+
else if (config.SplitRoutingMode == L"whitelist")
470+
{
471+
doc["fakeip-dns-server"]["param"]["tcp_map_back"].push_back("geoip-dispatcher.tcp");
472+
doc["fakeip-dns-server"]["param"]["udp_map_back"].push_back("geoip-dispatcher.udp");
473+
}
474+
else if (config.SplitRoutingMode == L"overseas")
475+
{
476+
doc["geoip-dispatcher"]["param"]["rules"]["cn"] = "proxy";
477+
doc["geoip-dispatcher"]["param"]["fallback"]["tcp"] = "direct-forward.tcp";
478+
doc["geoip-dispatcher"]["param"]["fallback"]["udp"] = "direct-forward.udp";
479+
doc["fakeip-dns-server"]["param"]["tcp_map_back"].push_back("geoip-dispatcher.tcp");
480+
doc["fakeip-dns-server"]["param"]["udp_map_back"].push_back("geoip-dispatcher.udp");
481+
}
482+
doc["geoip-dispatcher"]["param"]["source"] = to_string(config.SplitRoutingRuleset);
483+
374484
if (config.OutboundType == L"ss")
375485
{
376-
doc["main-forward"]["param"]["tcp_next"] = "ss-client.tcp";
486+
doc["proxy-forward"]["param"]["tcp_next"] = "ss-client.tcp";
377487
}
378488
else if (config.OutboundType == L"http")
379489
{
380-
doc["main-forward"]["param"]["tcp_next"] = "http-proxy-client.tcp";
490+
doc["proxy-forward"]["param"]["tcp_next"] = "http-proxy-client.tcp";
381491
}
382492
else if (config.OutboundType == L"trojan")
383493
{
384-
doc["main-forward"]["param"]["tcp_next"] = "trojan-client.tcp";
494+
doc["proxy-forward"]["param"]["tcp_next"] = "trojan-client.tcp";
385495
doc["proxy-redir"]["param"]["tcp_next"] = "client-tls.tcp";
386496
doc["client-tls"]["param"]["alpn"] = {"h2", "http/1.1"};
387497
}
388498
else if (config.OutboundType == L"vmess_ws_tls")
389499
{
390-
doc["main-forward"]["param"]["tcp_next"] = "vmess-client.tcp";
500+
doc["proxy-forward"]["param"]["tcp_next"] = "vmess-client.tcp";
391501
doc["proxy-redir"]["param"]["tcp_next"] = "ws-client.tcp";
392502
doc["client-tls"]["param"]["alpn"] = {"http/1.1"};
393503
}

YtFlowApp/NewProfilePage.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ namespace winrt::YtFlowApp::implementation
66
{
77
struct NewProfileConfig
88
{
9+
hstring InboundMode;
10+
hstring SplitRoutingMode;
11+
hstring SplitRoutingRuleset;
12+
hstring RuleResolver;
913
hstring OutboundType;
1014
};
1115
struct NewProfilePage : NewProfilePageT<NewProfilePage>

YtFlowApp/NewProfilePage.xaml

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
xmlns:local="using:YtFlowApp"
66
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
77
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
89
mc:Ignorable="d"
910
Loaded="Page_Loaded"
1011
Unloaded="Page_Unloaded">
@@ -53,8 +54,10 @@
5354
<TextBlock Margin="{StaticResource SubheaderMargin}" Style="{ThemeResource BaseTextBlockStyle}">
5455
Inbound mode
5556
</TextBlock>
56-
<RadioButton GroupName="InboundModeGroup" IsChecked="True" Tag="fake">UWP VPN, Fake IP range</RadioButton>
57-
<RadioButton GroupName="InboundModeGroup" Tag="full">UWP VPN, Full IP range</RadioButton>
57+
<muxc:RadioButtons x:Name="InboundModeButtons" SelectedIndex="0">
58+
<RadioButton Tag="fake">UWP VPN, Fake IP range</RadioButton>
59+
<RadioButton Tag="full">UWP VPN, Full IP range</RadioButton>
60+
</muxc:RadioButtons>
5861
<TextBlock Margin="{StaticResource SubheaderMargin}" Style="{ThemeResource BaseTextBlockStyle}">
5962
Additional Inbound ports
6063
</TextBlock>
@@ -88,14 +91,16 @@
8891
</TextBlock>
8992
<StackPanel Orientation="Horizontal">
9093
<Button Content="Select..." Click="SelectRulesetButton_Click" />
91-
<TextBlock x:Name="SelectedRulesetNameText" Margin="8, 0, 0, 0" />
94+
<TextBlock x:Name="SelectedRulesetNameText" Margin="8, 0, 0, 0" VerticalAlignment="Center" />
9295
</StackPanel>
9396
<TextBlock Margin="{StaticResource SubheaderMargin}" Style="{ThemeResource BaseTextBlockStyle}">
94-
Resolver for Rule Matching
97+
DNS provider for Rule Matching
9598
</TextBlock>
96-
<RadioButton GroupName="RuleResolver" Tag="local">Local Resolver</RadioButton>
97-
<RadioButton GroupName="RuleResolver" Tag="1111">1.1.1.1 (DoH)</RadioButton>
98-
<RadioButton GroupName="RuleResolver" Tag="ali">Alibaba Cloud Public DNS (DoH)</RadioButton>
99+
<ComboBox x:Name="RuleResolverComboBox" SelectedIndex="1">
100+
<ComboBoxItem Tag="local">Local Resolver</ComboBoxItem>
101+
<ComboBoxItem Tag="1111">1.1.1.1 (DoH)</ComboBoxItem>
102+
<ComboBoxItem Tag="ali">Alibaba Cloud Public DNS (DoH)</ComboBoxItem>
103+
</ComboBox>
99104
</StackPanel>
100105

101106
<StackPanel x:Name="RightPanel" Grid.Row="3" Grid.Column="0">
@@ -137,7 +142,7 @@
137142
</StackPanel>
138143
</StackPanel>
139144

140-
<local:NewProfileRulesetControl x:Name="RulesetDialog" />
145+
<local:NewProfileRulesetControl x:Name="RulesetDialog" Grid.RowSpan="5" />
141146
</Grid>
142147

143148
<VisualStateManager.VisualStateGroups>

YtFlowApp/NewProfileRulesetControl.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ namespace winrt::YtFlowApp::implementation
2323
{
2424
bool NewProfileRulesetControl::RulesetSelected()
2525
{
26-
return false;
26+
return m_rulesetSelected;
2727
}
2828
hstring NewProfileRulesetControl::RulesetName()
2929
{
30-
return L"";
30+
return m_rulesetName;
3131
}
3232

3333
std::string_view NewProfileRulesetControl::GetResourceKeyFromSelectedRuleset()
@@ -170,6 +170,7 @@ namespace winrt::YtFlowApp::implementation
170170

171171
void NewProfileRulesetControl::ContentDialog_Opened(ContentDialog const &, ContentDialogOpenedEventArgs const &)
172172
{
173+
m_rulesetSelected = false;
173174
m_selectionChangeToken =
174175
SelectionComboBox().SelectionChanged({this, &NewProfileRulesetControl::SelectionComboBox_SelectionChanged});
175176
InitSelectedRuleset();
@@ -419,4 +420,10 @@ namespace winrt::YtFlowApp::implementation
419420
lifetime->CancelUpdateButton().Visibility(Visibility::Collapsed);
420421
lifetime->UpdateProgressBar().Visibility(Visibility::Collapsed);
421422
}
423+
void NewProfileRulesetControl::ContentDialog_PrimaryButtonClick(ContentDialog const &,
424+
ContentDialogButtonClickEventArgs const &)
425+
{
426+
m_rulesetSelected = true;
427+
m_rulesetName = to_hstring(GetResourceKeyFromSelectedRuleset());
428+
}
422429
}

YtFlowApp/NewProfileRulesetControl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,15 @@ namespace winrt::YtFlowApp::implementation
2626
winrt::Windows::UI::Xaml::RoutedEventArgs const &e);
2727
fire_and_forget UpdateButton_Click(winrt::Windows::Foundation::IInspectable const &sender,
2828
winrt::Windows::UI::Xaml::RoutedEventArgs const &e);
29+
void ContentDialog_PrimaryButtonClick(
30+
winrt::Windows::UI::Xaml::Controls::ContentDialog const &sender,
31+
winrt::Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs const &args);
2932

3033
private:
3134
static inline Windows::Storage::StorageFolder m_resourceFolder{nullptr};
3235

36+
bool m_rulesetSelected{false};
37+
hstring m_rulesetName;
3338
Windows::Web::Http::HttpClient m_client{nullptr};
3439
event_token m_selectionChangeToken;
3540
std::vector<FfiResource> m_resources;

YtFlowApp/NewProfileRulesetControl.xaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@
99
xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)"
1010
xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)"
1111
Title="Select Ruleset"
12+
Style="{ThemeResource DefaultContentDialogStyle}"
1213
PrimaryButtonText="Select"
1314
IsPrimaryButtonEnabled="False"
1415
contract7NotPresent:SecondaryButtonText="Close"
1516
Opened="ContentDialog_Opened"
1617
Closing="ContentDialog_Closing"
18+
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
1719
>
1820
<contract7Present:ContentDialog.SecondaryButtonCommand>
1921
<contract7Present:StandardUICommand Kind="Close"/>
@@ -29,8 +31,10 @@
2931
<TextBlock x:Name="LastUpdatedText" Margin="4, 0, 0, 0" Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" />
3032
</StackPanel>
3133
<ProgressBar x:Name="UpdateProgressBar" Visibility="Collapsed" />
32-
<Button x:Name="UpdateButton" Margin="0, 4, 0, 4" IsEnabled="False" Click="UpdateButton_Click">Update</Button>
33-
<Button x:Name="CancelUpdateButton" Visibility="Collapsed" Margin="0, 4, 0, 0" Click="CancelUpdateButton_Click">Cancel</Button>
34+
<StackPanel Orientation="Horizontal">
35+
<Button x:Name="UpdateButton" Margin="0, 4, 8, 4" IsEnabled="False" Click="UpdateButton_Click">Update</Button>
36+
<Button x:Name="CancelUpdateButton" Visibility="Collapsed" Margin="0, 4, 0, 4" Click="CancelUpdateButton_Click">Cancel</Button>
37+
</StackPanel>
3438
<TextBlock
3539
x:Name="UpdateErrorText"
3640
MaxHeight="50"

0 commit comments

Comments
 (0)