feat(outbound): sync DNS outbound config with Xray core changes

Rename the DNS rule wire key qtype to qType (reading the legacy qtype on parse for back-compat), add the new rCode response-code field for the return action (omitted when zero), and rename the reject action to return. Align the DNS rule action set across the form dropdown, schema, and adapter to the core's valid values (direct/drop/return/hijack), dropping the never-valid rejectIPv4/rejectIPv6 entries.
This commit is contained in:
MHSanaei
2026-06-01 10:24:35 +02:00
parent 32f96298f8
commit 2bb9ed1cda
6 changed files with 42 additions and 25 deletions
@@ -197,7 +197,7 @@ describe('outbound-form-adapter: round-trip', () => {
expect(withType.settings).toEqual({ response: { type: 'http' } });
});
it('dns rules normalize qtype numeric strings and split domains', () => {
it('dns rules normalize qType numeric strings, split domains, carry rCode', () => {
const wire = {
protocol: 'dns',
settings: {
@@ -205,16 +205,26 @@ describe('outbound-form-adapter: round-trip', () => {
rewriteAddress: '1.1.1.1',
rewritePort: 53,
rules: [
{ action: 'direct', qtype: 'A,AAAA', domain: ['example.com', 'ext.org'] },
{ action: 'reject', qtype: 28, domain: 'blocked.com' },
{ action: 'direct', qType: 'A,AAAA', domain: ['example.com', 'ext.org'] },
{ action: 'return', qType: 28, domain: 'blocked.com', rCode: 3 },
],
},
};
const back = formValuesToWirePayload(rawOutboundToFormValues(wire));
const settings = back.settings as Record<string, unknown>;
const rules = settings.rules as Array<Record<string, unknown>>;
expect(rules[0]).toEqual({ action: 'direct', qtype: 'A,AAAA', domain: ['example.com', 'ext.org'] });
expect(rules[1]).toEqual({ action: 'reject', qtype: 28, domain: ['blocked.com'] });
expect(rules[0]).toEqual({ action: 'direct', qType: 'A,AAAA', domain: ['example.com', 'ext.org'] });
expect(rules[1]).toEqual({ action: 'return', qType: 28, domain: ['blocked.com'], rCode: 3 });
});
it('dns rules read the legacy qtype wire key for back-compat', () => {
const wire = {
protocol: 'dns',
settings: { rules: [{ action: 'direct', qtype: 'TXT' }] },
};
const back = formValuesToWirePayload(rawOutboundToFormValues(wire));
const rules = (back.settings as Record<string, unknown>).rules as Array<Record<string, unknown>>;
expect(rules[0]).toEqual({ action: 'direct', qType: 'TXT' });
});
it('freedom emits domainStrategy/redirect/fragment conditionally', () => {