Files
chen08209 8068e686a3 feat(core): check services and the outbound IP through the Core
Changelog: Proxied service checks and outbound IP risk
2026-10-02 02:51:32 +08:00

52 lines
1.5 KiB
Dart

import 'package:fl_clash/common/service_probe.dart';
import 'package:fl_clash/models/models.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'core.dart';
import 'route_state.dart';
import 'routed_probe.dart';
part 'generated/outbound_ip.g.dart';
/// Keyed by the outbound a lookup pins: a node name, `DIRECT`, or
/// [routedOutbound] for whatever the rules pick right now.
@Riverpod(keepAlive: true)
class OutboundIpProbe extends _$OutboundIpProbe
with RoutedProbe<String, IpInfo> {
@override
RoutedProbeState<String, IpInfo> build() => buildProbe();
@override
Future<Map<String, ProbeAnswer<IpInfo>>> probe(
String target,
RouteState route,
) async {
final proxyName = target == routedOutbound && !route.proxied
? directOutbound
: target;
final result = await lookupOutboundIp(
ref.read(coreHandlerProvider),
proxyName,
);
final value = parseOutboundIp(result);
final chains = result?.chains ?? const <String>[];
final exit = chains.firstOrNull;
return {
target: ProbeAnswer(
value: value,
coreEpoch: result?.coreEpoch,
picksVersion: result?.picksVersion,
chains: chains,
),
// A node leaves through the same address whatever it is asked for.
if (value != null && exit != null && exit != target)
exit: ProbeAnswer(
value: value,
coreEpoch: result?.coreEpoch,
picksVersion: result?.picksVersion,
chains: [exit],
),
};
}
}