Skip to main content

c/
ns_parse.rs

1// Copyright (c) 2026 Meng Zhuo
2// SPDX-License-Identifier: BSD-3-Clause
3
4// Parsing of DNS messages for the ns_* API from <arpa/nameser.h>.
5
6pub const NS_MAXDNAME_V: usize = 1025;
7const NS_INT16SZ_V: usize = 2;
8const NS_INT32SZ_V: usize = 4;
9const NS_S_MAX_V: usize = 4;
10
11#[repr(C)]
12pub struct NsMsg {
13    pub _msg: *const u8,
14    pub _eom: *const u8,
15    pub _id: u16,
16    pub _flags: u16,
17    pub _counts: [u16; NS_S_MAX_V],
18    pub _sections: [*const u8; NS_S_MAX_V],
19    pub _sect: c_int,
20    pub _rrnum: c_int,
21    pub _msg_ptr: *const u8,
22}
23
24#[repr(C)]
25pub struct NsRr {
26    pub name: [c_char; NS_MAXDNAME_V],
27    pub type_: u16,
28    pub rr_class: u16,
29    pub ttl: u32,
30    pub rdlength: u16,
31    __pad: u16,
32    pub rdata: *const u8,
33}
34
35#[no_mangle]
36pub static _ns_flagdata: [[c_int; 2]; 16] = [
37    [0x8000, 15],
38    [0x7800, 11],
39    [0x0400, 10],
40    [0x0200, 9],
41    [0x0100, 8],
42    [0x0080, 7],
43    [0x0040, 6],
44    [0x0020, 5],
45    [0x0010, 4],
46    [0x000f, 0],
47    [0x0000, 0],
48    [0x0000, 0],
49    [0x0000, 0],
50    [0x0000, 0],
51    [0x0000, 0],
52    [0x0000, 0],
53];
54
55unsafe fn ns_skiprr_inner(ptr: *const u8, eom: *const u8, section: c_int, mut count: c_int) -> c_int {
56    let mut p = ptr;
57    while count > 0 {
58        count -= 1;
59        let r = dn_skipname(p, eom);
60        if r < 0 { return -1; }
61        if r as usize + 2 * NS_INT16SZ_V > eom as usize - p as usize { return -1; }
62        p = p.add(r as usize + 2 * NS_INT16SZ_V);
63        if section != 0 {
64            if NS_INT32SZ_V + NS_INT16SZ_V > eom as usize - p as usize { return -1; }
65            p = p.add(NS_INT32SZ_V);
66            let rdlen = ns_get16(p) as usize;
67            p = p.add(NS_INT16SZ_V);
68            if rdlen > eom as usize - p as usize { return -1; }
69            p = p.add(rdlen);
70        }
71    }
72    (p as usize - ptr as usize) as c_int
73}
74
75#[no_mangle]
76pub unsafe extern "C" fn ns_skiprr(ptr: *const u8, eom: *const u8, section: c_int, count: c_int) -> c_int {
77    let r = ns_skiprr_inner(ptr, eom, section, count);
78    if r < 0 { ERRNO!() = 90; } // EMSGSIZE
79    r
80}
81
82#[no_mangle]
83pub unsafe extern "C" fn ns_initparse(msg: *const u8, msglen: c_int, handle: *mut NsMsg) -> c_int {
84    if msg.is_null() || handle.is_null() || msglen < 0 {
85        ERRNO!() = 90;
86        return -1;
87    }
88    (*handle)._msg = msg;
89    (*handle)._eom = msg.add(msglen as usize);
90    if (msglen as usize) < (2 + NS_S_MAX_V) * NS_INT16SZ_V {
91        ERRNO!() = 90;
92        return -1;
93    }
94    let mut p = msg;
95    (*handle)._id = ns_get16(p) as u16;
96    p = p.add(2);
97    (*handle)._flags = ns_get16(p) as u16;
98    p = p.add(2);
99    for i in 0..NS_S_MAX_V {
100        (*handle)._counts[i] = ns_get16(p) as u16;
101        p = p.add(2);
102    }
103    for i in 0..NS_S_MAX_V {
104        if (*handle)._counts[i] != 0 {
105            (*handle)._sections[i] = p;
106            let r = ns_skiprr_inner(p, (*handle)._eom, i as c_int, (*handle)._counts[i] as c_int);
107            if r < 0 {
108                ERRNO!() = 90;
109                return -1;
110            }
111            p = p.add(r as usize);
112        } else {
113            (*handle)._sections[i] = core::ptr::null();
114        }
115    }
116    if p != (*handle)._eom {
117        ERRNO!() = 90;
118        return -1;
119    }
120    (*handle)._sect = NS_S_MAX_V as c_int;
121    (*handle)._rrnum = -1;
122    (*handle)._msg_ptr = core::ptr::null();
123    0
124}
125
126#[no_mangle]
127pub unsafe extern "C" fn ns_name_uncompress(
128    msg: *const u8,
129    eom: *const u8,
130    src: *const u8,
131    dst: *mut c_char,
132    dstsiz: usize,
133) -> c_int {
134    let r = crate::dn_expand(msg, eom, src, dst, dstsiz as c_int);
135    if r < 0 { ERRNO!() = 90; }
136    r
137}
138
139#[no_mangle]
140pub unsafe extern "C" fn ns_parserr(handle: *mut NsMsg, section: c_int, rrnum_in: c_int, rr: *mut NsRr) -> c_int {
141    if handle.is_null() || rr.is_null() || section < 0 || section >= NS_S_MAX_V as c_int {
142        ERRNO!() = 19; // ENODEV
143        return -1;
144    }
145    let sec = section as usize;
146    if section != (*handle)._sect {
147        (*handle)._sect = section;
148        (*handle)._rrnum = 0;
149        (*handle)._msg_ptr = (*handle)._sections[sec];
150    }
151    let mut rrnum = rrnum_in;
152    if rrnum == -1 { rrnum = (*handle)._rrnum; }
153    if rrnum < 0 || rrnum >= (*handle)._counts[sec] as c_int {
154        ERRNO!() = 19;
155        return -1;
156    }
157    if rrnum < (*handle)._rrnum {
158        (*handle)._rrnum = 0;
159        (*handle)._msg_ptr = (*handle)._sections[sec];
160    }
161    if rrnum > (*handle)._rrnum {
162        let r = ns_skiprr_inner(
163            (*handle)._msg_ptr,
164            (*handle)._eom,
165            section,
166            rrnum - (*handle)._rrnum,
167        );
168        if r < 0 {
169            ERRNO!() = 90;
170            return -1;
171        }
172        (*handle)._msg_ptr = (*handle)._msg_ptr.add(r as usize);
173        (*handle)._rrnum = rrnum;
174    }
175    let r = ns_name_uncompress(
176        (*handle)._msg,
177        (*handle)._eom,
178        (*handle)._msg_ptr,
179        (*rr).name.as_mut_ptr(),
180        NS_MAXDNAME_V,
181    );
182    if r < 0 { return -1; }
183    (*handle)._msg_ptr = (*handle)._msg_ptr.add(r as usize);
184    if 2 * NS_INT16SZ_V > (*handle)._eom as usize - (*handle)._msg_ptr as usize {
185        ERRNO!() = 90;
186        return -1;
187    }
188    (*rr).type_ = ns_get16((*handle)._msg_ptr) as u16;
189    (*handle)._msg_ptr = (*handle)._msg_ptr.add(2);
190    (*rr).rr_class = ns_get16((*handle)._msg_ptr) as u16;
191    (*handle)._msg_ptr = (*handle)._msg_ptr.add(2);
192    if section != 0 {
193        if NS_INT32SZ_V + NS_INT16SZ_V > (*handle)._eom as usize - (*handle)._msg_ptr as usize {
194            ERRNO!() = 90;
195            return -1;
196        }
197        (*rr).ttl = ns_get32((*handle)._msg_ptr) as u32;
198        (*handle)._msg_ptr = (*handle)._msg_ptr.add(4);
199        (*rr).rdlength = ns_get16((*handle)._msg_ptr) as u16;
200        (*handle)._msg_ptr = (*handle)._msg_ptr.add(2);
201        if (*rr).rdlength as usize > (*handle)._eom as usize - (*handle)._msg_ptr as usize {
202            ERRNO!() = 90;
203            return -1;
204        }
205        (*rr).rdata = (*handle)._msg_ptr;
206        (*handle)._msg_ptr = (*handle)._msg_ptr.add((*rr).rdlength as usize);
207    } else {
208        (*rr).ttl = 0;
209        (*rr).rdlength = 0;
210        (*rr).rdata = core::ptr::null();
211    }
212    (*handle)._rrnum += 1;
213    if (*handle)._rrnum > (*handle)._counts[sec] as c_int {
214        (*handle)._sect = section + 1;
215        if (*handle)._sect == NS_S_MAX_V as c_int {
216            (*handle)._rrnum = -1;
217            (*handle)._msg_ptr = core::ptr::null();
218        } else {
219            (*handle)._rrnum = 0;
220        }
221    }
222    0
223}