1mod dns;
6
7use core::{cell::Cell, fmt::Write, mem, net::Ipv4Addr, ptr, str};
8
9use alloc::{boxed::Box, str::SplitWhitespace, string::ToString, vec::Vec};
10
11use crate::{
12 c_str::{CStr, CString},
13 error::ResultExt,
14 header::{
15 arpa_inet::inet_aton,
16 bits_arpainet::{htons, ntohl},
17 bits_safamily_t::sa_family_t,
18 errno::*,
19 fcntl::O_RDONLY,
20 netinet_in::{in_addr, sockaddr_in},
21 stdlib::atoi,
22 strings::strcasecmp,
23 sys_socket::{constants::AF_INET, sockaddr, socklen_t},
24 unistd::SEEK_SET,
25 },
26 platform::{
27 self, Pal, Sys,
28 rlb::{Line, RawLineBuffer},
29 types::{c_char, c_int, c_void, uint32_t},
30 },
31 raw_cell::RawCell,
32};
33
34use crate::header::netinet_in::sockaddr_in6;
35
36#[cfg(target_os = "linux")]
37#[path = "linux.rs"]
38pub mod sys;
39
40#[cfg(target_os = "redox")]
41#[path = "redox.rs"]
42pub mod sys;
43
44pub use self::host::*;
45pub mod host;
46
47pub use self::lookup::*;
48pub mod lookup;
49
50#[repr(C)]
52pub struct hostent {
53 h_name: *mut c_char,
54 h_aliases: *mut *mut c_char,
55 h_addrtype: c_int,
56 h_length: c_int,
57 h_addr_list: *mut *mut c_char,
58}
59
60#[repr(C)]
62pub struct netent {
63 n_name: *mut c_char, n_aliases: *mut *mut c_char, n_addrtype: c_int, n_net: uint32_t, }
68
69#[repr(C)]
71pub struct protoent {
72 p_name: *mut c_char, p_aliases: *mut *mut c_char, p_proto: c_int, }
76
77#[repr(C)]
79pub struct servent {
80 s_name: *mut c_char, s_aliases: *mut *mut c_char, s_port: c_int, s_proto: *mut c_char, }
85
86#[repr(C)]
88#[derive(Debug)]
89pub struct addrinfo {
90 ai_flags: c_int, ai_family: c_int, ai_socktype: c_int, ai_protocol: c_int, ai_addrlen: socklen_t, ai_canonname: *mut c_char, ai_addr: *mut sockaddr, ai_next: *mut addrinfo, }
99
100pub const AI_PASSIVE: c_int = 0x0001;
101pub const AI_CANONNAME: c_int = 0x0002;
102pub const AI_NUMERICHOST: c_int = 0x0004;
103pub const AI_V4MAPPED: c_int = 0x0008;
104pub const AI_ALL: c_int = 0x0010;
105pub const AI_ADDRCONFIG: c_int = 0x0020;
106pub const AI_NUMERICSERV: c_int = 0x0400;
107
108pub const EAI_BADFLAGS: c_int = -1;
109pub const EAI_NONAME: c_int = -2;
110pub const EAI_AGAIN: c_int = -3;
111pub const EAI_FAIL: c_int = -4;
112pub const EAI_NODATA: c_int = -5;
113pub const EAI_FAMILY: c_int = -6;
114pub const EAI_SOCKTYPE: c_int = -7;
115pub const EAI_SERVICE: c_int = -8;
116pub const EAI_ADDRFAMILY: c_int = -9;
117pub const EAI_MEMORY: c_int = -10;
118pub const EAI_SYSTEM: c_int = -11;
119pub const EAI_OVERFLOW: c_int = -12;
120
121pub const NI_MAXHOST: c_int = 1025;
122pub const NI_MAXSERV: c_int = 32;
123
124pub const NI_NUMERICHOST: c_int = 0x0001;
125pub const NI_NUMERICSERV: c_int = 0x0002;
126pub const NI_NOFQDN: c_int = 0x0004;
127pub const NI_NAMEREQD: c_int = 0x0008;
128pub const NI_DGRAM: c_int = 0x0010;
129
130static mut NETDB: c_int = 0;
131pub static mut NET_ENTRY: netent = netent {
132 n_name: ptr::null_mut(),
133 n_aliases: ptr::null_mut(),
134 n_addrtype: 0,
135 n_net: 0,
136};
137pub static NET_NAME: RawCell<Option<Vec<u8>>> = RawCell::new(None);
138pub static NET_ALIASES: RawCell<Option<Vec<Vec<u8>>>> = RawCell::new(None);
139pub static mut NET_ADDR: Option<u32> = None;
140static mut N_POS: usize = 0;
141static mut NET_STAYOPEN: c_int = 0;
142
143#[thread_local]
144pub static H_ERRNO: Cell<c_int> = Cell::new(0);
145const H_UNSET: c_int = 0;
146pub const HOST_NOT_FOUND: c_int = 1;
147pub const NO_DATA: c_int = 2;
148pub const NO_RECOVERY: c_int = 3;
149pub const TRY_AGAIN: c_int = 4;
150
151const SOCKLEN_AF_INET4: socklen_t = 4;
153const SOCKLEN_AF_INET6: socklen_t = 16;
154
155static mut PROTODB: c_int = 0;
156static mut PROTO_ENTRY: protoent = protoent {
157 p_name: ptr::null_mut(),
158 p_aliases: ptr::null_mut(),
159 p_proto: 0 as c_int,
160};
161static PROTO_NAME: RawCell<Option<Vec<u8>>> = RawCell::new(None);
162static PROTO_ALIASES: RawCell<Option<Vec<Vec<u8>>>> = RawCell::new(None);
163static mut PROTO_NUM: Option<c_int> = None;
164static mut P_POS: usize = 0;
165static mut PROTO_STAYOPEN: c_int = 0;
166
167static mut SERVDB: c_int = 0;
168static mut SERV_ENTRY: servent = servent {
169 s_name: ptr::null_mut(),
170 s_aliases: ptr::null_mut(),
171 s_port: 0 as c_int,
172 s_proto: ptr::null_mut(),
173};
174static SERV_NAME: RawCell<Option<Vec<u8>>> = RawCell::new(None);
175static SERV_ALIASES: RawCell<Option<Vec<Vec<u8>>>> = RawCell::new(None);
176static mut SERV_PORT: Option<c_int> = None;
177static SERV_PROTO: RawCell<Option<Vec<u8>>> = RawCell::new(None);
178static mut S_POS: usize = 0;
179static mut SERV_STAYOPEN: c_int = 0;
180
181fn bytes_to_box_str(bytes: &[u8]) -> Box<str> {
182 Box::from(core::str::from_utf8(bytes).unwrap_or(""))
183}
184
185#[unsafe(no_mangle)]
187pub unsafe extern "C" fn endnetent() {
188 if let Ok(()) = Sys::close(unsafe { NETDB }) {}; unsafe { NETDB = 0 };
190}
191
192#[unsafe(no_mangle)]
194pub unsafe extern "C" fn endprotoent() {
195 if let Ok(()) = Sys::close(unsafe { PROTODB }) {}; unsafe { PROTODB = 0 };
197}
198
199#[unsafe(no_mangle)]
201pub unsafe extern "C" fn endservent() {
202 if let Ok(()) = Sys::close(unsafe { SERVDB }) {}; unsafe { SERVDB = 0 };
204}
205
206#[unsafe(no_mangle)]
226#[deprecated]
227pub unsafe extern "C" fn gethostbyaddr(
228 v: *const c_void,
229 length: socklen_t,
230 format: c_int,
231) -> *mut hostent {
232 assert!(
233 !v.is_null(),
234 "`gethostbyaddr()` called with null `v` (in_addr)"
235 );
236 if length != SOCKLEN_AF_INET4 {
242 H_ERRNO.set(NO_RECOVERY);
243 return ptr::null_mut();
244 }
245 let addr: in_addr = unsafe { (*(v as *mut in_addr)).clone() };
246
247 let mut p: *mut hostent;
249 unsafe { sethostent(HOST_STAYOPEN) };
250 while {
251 p = unsafe { gethostent() };
252 !p.is_null()
253 } {
254 let mut cp = unsafe { (*p).h_addr_list };
255 loop {
256 if cp.is_null() {
257 break;
258 }
259 if (unsafe { *cp }).is_null() {
260 break;
261 }
262 let mut cp_slice: [c_char; 4] = [0; 4];
263 unsafe { (*cp).copy_to(cp_slice.as_mut_ptr(), 4) };
264 #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
265 let cp_s_addr = unsafe { mem::transmute::<[c_char; 4], u32>(cp_slice) };
266 #[cfg(any(target_arch = "riscv64", target_arch = "aarch64"))]
267 let cp_s_addr = u32::from_ne_bytes(cp_slice);
268 if cp_s_addr == addr.s_addr {
269 unsafe { sethostent(HOST_STAYOPEN) };
270 return p;
271 }
272 cp = unsafe { cp.offset(1) };
273 }
274 }
275
276 let mut _host_aliases: Vec<Vec<u8>> = vec![vec![b'\0']];
278 let mut host_aliases: Vec<*mut c_char> = vec![ptr::null_mut()];
279 unsafe { HOST_ALIASES.unsafe_set(Some(_host_aliases)) };
280
281 match lookup_addr(addr.clone()).map(|host_names| host_names.into_iter().next()) {
282 Ok(Some(host_name)) => {
283 unsafe { _HOST_ADDR_LIST = addr.s_addr.to_ne_bytes() };
284 unsafe {
285 HOST_ADDR_LIST = [(&raw mut _HOST_ADDR_LIST).cast::<c_char>(), ptr::null_mut()]
286 };
287 unsafe { HOST_NAME.unsafe_set(Some(host_name)) };
288 unsafe {
289 HOST_ENTRY = hostent {
290 h_name: HOST_NAME
291 .unsafe_mut()
292 .as_mut()
293 .unwrap()
294 .as_mut_ptr()
295 .cast::<c_char>(),
296 h_aliases: host_aliases.as_mut_slice().as_mut_ptr(),
297 h_addrtype: format,
298 h_length: length as i32,
299 h_addr_list: (&raw mut HOST_ADDR_LIST).cast(),
300 }
301 };
302 &raw mut HOST_ENTRY
303 }
304 Ok(None) => {
307 H_ERRNO.set(HOST_NOT_FOUND);
308 ptr::null_mut()
309 }
310 Err(e) => {
311 H_ERRNO.set(NO_RECOVERY);
313 ptr::null_mut()
314 }
315 }
316}
317
318#[unsafe(no_mangle)]
335#[deprecated]
336pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut hostent {
337 let name_cstr = unsafe {
338 CStr::from_nullable_ptr(name).expect("gethostbyname() called with a NULL pointer")
339 };
340 let Ok(name_str) = str::from_utf8(name_cstr.to_bytes()) else {
341 H_ERRNO.set(NO_RECOVERY);
342 return ptr::null_mut();
343 };
344
345 if let Some(s_addr) = parse_ipv4_string(name_str) {
349 let addr = in_addr { s_addr };
350 return unsafe {
351 #[allow(deprecated)]
352 gethostbyaddr(ptr::from_ref(&addr).cast::<c_void>(), 4, AF_INET)
353 };
354 }
355
356 let mut p: *mut hostent;
358 unsafe { sethostent(HOST_STAYOPEN) };
359 while {
360 p = unsafe { gethostent() };
361 !p.is_null()
362 } {
363 if unsafe { strcasecmp((*p).h_name, name) } == 0 {
364 unsafe { sethostent(HOST_STAYOPEN) };
365 return p;
366 }
367 let mut cp = unsafe { (*p).h_aliases };
368 loop {
369 if cp.is_null() {
370 break;
371 }
372 if (unsafe { *cp }).is_null() {
373 break;
374 }
375 if unsafe { strcasecmp(*cp, name) } == 0 {
376 unsafe { sethostent(HOST_STAYOPEN) };
377 return p;
378 }
379 cp = unsafe { cp.offset(1) };
380 }
381 }
382
383 let host = match lookup_host(name_str) {
384 Ok(lookuphost) => lookuphost,
385 Err(e) => {
386 H_ERRNO.set(NO_RECOVERY);
387 return ptr::null_mut();
388 }
389 };
390 let host_addr = match host.into_iter().next() {
391 Some(result) => result,
392 None => {
393 H_ERRNO.set(HOST_NOT_FOUND);
394 return ptr::null_mut();
395 }
396 };
397
398 let host_name: Vec<u8> = name_cstr.to_bytes().to_vec();
399 unsafe { HOST_NAME.unsafe_set(Some(host_name)) };
400 unsafe { _HOST_ADDR_LIST = host_addr.s_addr.to_ne_bytes() };
401 unsafe { HOST_ADDR_LIST = [(&raw mut _HOST_ADDR_LIST).cast::<c_char>(), ptr::null_mut()] };
402 unsafe { HOST_ADDR = Some(host_addr) };
403
404 let mut _host_aliases: Vec<Vec<u8>> = vec![vec![b'\0']];
406 let mut host_aliases: Vec<*mut c_char> = vec![ptr::null_mut(); 2];
407 unsafe { HOST_ALIASES.unsafe_set(Some(_host_aliases)) };
408
409 unsafe {
410 HOST_ENTRY = hostent {
411 h_name: HOST_NAME
412 .unsafe_mut()
413 .as_mut()
414 .unwrap()
415 .as_mut_ptr()
416 .cast::<c_char>(),
417 h_aliases: host_aliases.as_mut_slice().as_mut_ptr(),
418 h_addrtype: AF_INET,
419 h_length: 4,
420 h_addr_list: (&raw mut HOST_ADDR_LIST).cast(),
421 }
422 };
423 unsafe { sethostent(HOST_STAYOPEN) };
424 (&raw mut HOST_ENTRY).cast::<hostent>()
425}
426
427pub unsafe extern "C" fn getnetbyaddr(net: u32, net_type: c_int) -> *mut netent {
429 unimplemented!();
430}
431
432#[unsafe(no_mangle)]
434pub unsafe extern "C" fn getnetbyname(name: *const c_char) -> *mut netent {
435 let mut n: *mut netent;
436 unsafe { setnetent(NET_STAYOPEN) };
437 while {
438 n = unsafe { getnetent() };
439 !n.is_null()
440 } {
441 if unsafe { strcasecmp((*n).n_name, name) } == 0 {
442 unsafe { setnetent(NET_STAYOPEN) };
443 return n;
444 }
445 }
446 unsafe { setnetent(NET_STAYOPEN) };
447
448 platform::ERRNO.set(ENOENT);
449 ptr::null_mut::<netent>()
450}
451
452#[unsafe(no_mangle)]
454pub unsafe extern "C" fn getnetent() -> *mut netent {
455 if unsafe { NETDB } == 0 {
458 unsafe { NETDB = Sys::open(c"/etc/networks".into(), O_RDONLY, 0).or_minus_one_errno() };
459 }
460
461 let mut rlb = RawLineBuffer::new(unsafe { NETDB });
462 rlb.seek(unsafe { N_POS });
463
464 let mut r: Box<str> = Box::default();
465 while r.is_empty() || r.split_whitespace().next().is_none() || r.starts_with('#') {
466 r = match rlb.next() {
467 Line::Some(s) => bytes_to_box_str(s),
468 _ => {
469 if unsafe { NET_STAYOPEN } == 0 {
470 unsafe { endnetent() };
471 }
472 return ptr::null_mut();
473 }
474 };
475 }
476 rlb.next();
477 unsafe { N_POS = rlb.line_pos() };
478
479 let mut iter: SplitWhitespace = r.split_whitespace();
480
481 let net_name = iter.next().unwrap().bytes().chain(Some(b'\0')).collect();
482 unsafe { NET_NAME.unsafe_set(Some(net_name)) };
483
484 let addr_vec: Vec<u8> = iter.next().unwrap().bytes().chain(Some(b'\0')).collect();
485 let addr_cstr = addr_vec.as_slice().as_ptr().cast::<c_char>();
486 let mut addr = mem::MaybeUninit::uninit();
487 unsafe { inet_aton(addr_cstr, addr.as_mut_ptr()) };
488 let addr = unsafe { addr.assume_init() };
489 unsafe { NET_ADDR = Some(ntohl(addr.s_addr)) };
490
491 let mut _net_aliases: Vec<Vec<u8>> = iter
492 .map(|alias| alias.bytes().chain(Some(b'\0')).collect())
493 .collect();
494 let mut net_aliases: Vec<*mut c_char> = _net_aliases
495 .iter_mut()
496 .map(|x| x.as_mut_ptr().cast::<c_char>())
497 .chain(Some(ptr::null_mut()))
498 .collect();
499 unsafe { NET_ALIASES.unsafe_set(Some(_net_aliases)) };
500
501 unsafe {
502 NET_ENTRY = netent {
503 n_name: NET_NAME
504 .unsafe_mut()
505 .as_mut()
506 .unwrap()
507 .as_mut_ptr()
508 .cast::<c_char>(),
509 n_aliases: net_aliases.as_mut_slice().as_mut_ptr(),
510 n_addrtype: AF_INET,
511 n_net: uint32_t::from(NET_ADDR.unwrap()),
512 }
513 };
514 (&raw mut NET_ENTRY).cast::<netent>()
515}
516
517#[unsafe(no_mangle)]
519pub unsafe extern "C" fn getprotobyname(name: *const c_char) -> *mut protoent {
520 let mut p: *mut protoent;
521 unsafe { setprotoent(PROTO_STAYOPEN) };
522 while {
523 p = unsafe { getprotoent() };
524 !p.is_null()
525 } {
526 if unsafe { strcasecmp((*p).p_name, name) } == 0 {
527 unsafe { setprotoent(PROTO_STAYOPEN) };
528 return p;
529 }
530
531 let mut cp = unsafe { (*p).p_aliases };
532 loop {
533 if cp.is_null() {
534 unsafe { setprotoent(PROTO_STAYOPEN) };
535 break;
536 }
537 if (unsafe { *cp }).is_null() {
538 unsafe { setprotoent(PROTO_STAYOPEN) };
539 break;
540 }
541 if unsafe { strcasecmp(*cp, name) } == 0 {
542 unsafe { setprotoent(PROTO_STAYOPEN) };
543 return p;
544 }
545 cp = unsafe { cp.offset(1) };
546 }
547 }
548 unsafe { setprotoent(PROTO_STAYOPEN) };
549
550 platform::ERRNO.set(ENOENT);
551 ptr::null_mut::<protoent>()
552}
553
554#[unsafe(no_mangle)]
556pub unsafe extern "C" fn getprotobynumber(number: c_int) -> *mut protoent {
557 unsafe { setprotoent(PROTO_STAYOPEN) };
558 let mut p: *mut protoent;
559 while {
560 p = unsafe { getprotoent() };
561 !p.is_null()
562 } {
563 if unsafe { (*p).p_proto } == number {
564 unsafe { setprotoent(PROTO_STAYOPEN) };
565 return p;
566 }
567 }
568 unsafe { setprotoent(PROTO_STAYOPEN) };
569 platform::ERRNO.set(ENOENT);
570 ptr::null_mut::<protoent>()
571}
572
573#[unsafe(no_mangle)]
575pub unsafe extern "C" fn getprotoent() -> *mut protoent {
576 if unsafe { PROTODB } == 0 {
577 unsafe { PROTODB = Sys::open(c"/etc/protocols".into(), O_RDONLY, 0).or_minus_one_errno() };
578 }
579
580 let mut rlb = RawLineBuffer::new(unsafe { PROTODB });
581 rlb.seek(unsafe { P_POS });
582
583 let mut r: Box<str> = Box::default();
584 while r.is_empty() || r.split_whitespace().next().is_none() || r.starts_with('#') {
585 r = match rlb.next() {
586 Line::Some(s) => bytes_to_box_str(s),
587 _ => {
588 if unsafe { PROTO_STAYOPEN } == 0 {
589 unsafe { endprotoent() };
590 }
591 return ptr::null_mut();
592 }
593 };
594 }
595 rlb.next();
596 unsafe { P_POS = rlb.line_pos() };
597
598 let mut iter: SplitWhitespace = r.split_whitespace();
599
600 let mut proto_name: Vec<u8> = iter.next().unwrap().as_bytes().to_vec();
601 proto_name.push(b'\0');
602
603 let mut num = iter.next().unwrap().as_bytes().to_vec();
604 num.push(b'\0');
605 unsafe { PROTO_NUM = Some(atoi(num.as_mut_slice().as_mut_ptr().cast::<c_char>())) };
606
607 let mut _proto_aliases: Vec<Vec<u8>> = iter
608 .map(|alias| alias.bytes().chain(Some(b'\0')).collect())
609 .collect();
610 let mut proto_aliases: Vec<*mut i8> = _proto_aliases
611 .iter_mut()
612 .map(|x| x.as_mut_ptr().cast::<i8>())
613 .chain(Some(ptr::null_mut()))
614 .collect();
615
616 unsafe { PROTO_ALIASES.unsafe_set(Some(_proto_aliases)) };
617 unsafe { PROTO_NAME.unsafe_set(Some(proto_name)) };
618
619 unsafe {
620 PROTO_ENTRY = protoent {
621 p_name: PROTO_NAME
622 .unsafe_mut()
623 .as_mut()
624 .unwrap()
625 .as_mut_slice()
626 .as_mut_ptr()
627 .cast::<c_char>(),
628 p_aliases: proto_aliases
629 .as_mut_slice()
630 .as_mut_ptr()
631 .cast::<*mut c_char>(),
632 p_proto: PROTO_NUM.unwrap(),
633 }
634 };
635 if unsafe { PROTO_STAYOPEN } == 0 {
636 unsafe { endprotoent() };
637 }
638 (&raw mut PROTO_ENTRY).cast::<protoent>()
639}
640
641#[unsafe(no_mangle)]
643pub unsafe extern "C" fn getservbyname(name: *const c_char, proto: *const c_char) -> *mut servent {
644 unsafe { setservent(SERV_STAYOPEN) };
645 let mut p: *mut servent;
646 if proto.is_null() {
647 while {
648 p = unsafe { getservent() };
649 !p.is_null()
650 } {
651 if unsafe { strcasecmp((*p).s_name, name) } == 0 {
652 unsafe { setservent(SERV_STAYOPEN) };
653 return p;
654 }
655 }
656 } else {
657 while {
658 p = unsafe { getservent() };
659 !p.is_null()
660 } {
661 if unsafe { strcasecmp((*p).s_name, name) } == 0
662 && unsafe { strcasecmp((*p).s_proto, proto) } == 0
663 {
664 unsafe { setservent(SERV_STAYOPEN) };
665 return p;
666 }
667 }
668 }
669 unsafe { setservent(SERV_STAYOPEN) };
670 platform::ERRNO.set(ENOENT);
671 ptr::null_mut::<servent>()
672}
673
674#[unsafe(no_mangle)]
676pub unsafe extern "C" fn getservbyport(port: c_int, proto: *const c_char) -> *mut servent {
677 unsafe { setservent(SERV_STAYOPEN) };
678 let mut p: *mut servent;
679 if proto.is_null() {
680 while {
681 p = unsafe { getservent() };
682 !p.is_null()
683 } {
684 if unsafe { (*p).s_port } == port {
685 unsafe { setservent(SERV_STAYOPEN) };
686 return p;
687 }
688 }
689 } else {
690 while {
691 p = unsafe { getservent() };
692 !p.is_null()
693 } {
694 if unsafe { (*p).s_port } == port && unsafe { strcasecmp((*p).s_proto, proto) } == 0 {
695 unsafe { setservent(SERV_STAYOPEN) };
696 return p;
697 }
698 }
699 }
700 unsafe { setservent(SERV_STAYOPEN) };
701 platform::ERRNO.set(ENOENT);
702 ptr::null_mut()
703}
704
705#[unsafe(no_mangle)]
707pub unsafe extern "C" fn getservent() -> *mut servent {
708 if unsafe { SERVDB } == 0 {
709 unsafe { SERVDB = Sys::open(c"/etc/services".into(), O_RDONLY, 0).or_minus_one_errno() };
711 }
712 let mut rlb = RawLineBuffer::new(unsafe { SERVDB });
713 rlb.seek(unsafe { S_POS });
714
715 let r: Box<str> = Box::default();
716
717 loop {
718 let r = match rlb.next() {
719 Line::Some(s) => bytes_to_box_str(s),
720 _ => {
721 if unsafe { SERV_STAYOPEN } == 0 {
722 unsafe { endservent() };
723 }
724 return ptr::null_mut();
725 }
726 };
727
728 let mut iter = r.split_whitespace();
729 let serv_name = match iter.next() {
730 Some(serv_name) => serv_name.bytes().chain(Some(b'\0')).collect(),
731 None => continue,
732 };
733 let port_proto = match iter.next() {
734 Some(port_proto) => port_proto,
735 None => continue,
736 };
737 let mut split = port_proto.split('/');
738 let mut port: Vec<u8> = match split.next() {
739 Some(port) => port.bytes().chain(Some(b'\0')).collect(),
740 None => continue,
741 };
742 unsafe {
743 SERV_PORT = Some(u32::from(htons(
744 atoi(port.as_mut_slice().as_mut_ptr().cast::<c_char>()) as u16,
745 )) as i32)
746 };
747 let proto = match split.next() {
748 Some(proto) => proto.bytes().chain(Some(b'\0')).collect(),
749 None => continue,
750 };
751
752 rlb.next();
753 unsafe { S_POS = rlb.line_pos() };
754
755 let mut _serv_aliases: Vec<Vec<u8>> = vec![vec![b'\0']];
770 let mut serv_aliases: Vec<*mut i8> = vec![ptr::null_mut(); 2];
771
772 unsafe { SERV_ALIASES.unsafe_set(Some(_serv_aliases)) };
773 unsafe { SERV_NAME.unsafe_set(Some(serv_name)) };
774 unsafe { SERV_PROTO.unsafe_set(Some(proto)) };
775
776 unsafe {
777 SERV_ENTRY = servent {
778 s_name: SERV_NAME
779 .unsafe_mut()
780 .as_mut()
781 .unwrap()
782 .as_mut_slice()
783 .as_mut_ptr()
784 .cast::<c_char>(),
785 s_aliases: serv_aliases
786 .as_mut_slice()
787 .as_mut_ptr()
788 .cast::<*mut c_char>(),
789 s_port: SERV_PORT.unwrap(),
790 s_proto: SERV_PROTO
791 .unsafe_mut()
792 .as_mut()
793 .unwrap()
794 .as_mut_slice()
795 .as_mut_ptr()
796 .cast::<c_char>(),
797 }
798 };
799
800 if unsafe { SERV_STAYOPEN } == 0 {
801 unsafe { endservent() };
802 }
803 break (&raw mut SERV_ENTRY).cast::<servent>();
804 }
805}
806
807#[unsafe(no_mangle)]
809pub unsafe extern "C" fn setnetent(stayopen: c_int) {
810 unsafe { NET_STAYOPEN = stayopen };
811 if unsafe { NETDB } == 0 {
812 unsafe { NETDB = Sys::open(c"/etc/networks".into(), O_RDONLY, 0).or_minus_one_errno() }
813 } else {
814 if Sys::lseek(unsafe { NETDB }, 0, SEEK_SET).is_ok() {}; unsafe { N_POS = 0 };
816 }
817}
818
819#[unsafe(no_mangle)]
821pub unsafe extern "C" fn setprotoent(stayopen: c_int) {
822 unsafe { PROTO_STAYOPEN = stayopen };
823 if unsafe { PROTODB } == 0 {
824 unsafe { PROTODB = Sys::open(c"/etc/protocols".into(), O_RDONLY, 0).or_minus_one_errno() }
825 } else {
826 if Sys::lseek(unsafe { PROTODB }, 0, SEEK_SET).is_ok() {}; unsafe { P_POS = 0 };
828 }
829}
830
831#[unsafe(no_mangle)]
833pub unsafe extern "C" fn setservent(stayopen: c_int) {
834 unsafe { SERV_STAYOPEN = stayopen };
835 if unsafe { SERVDB } == 0 {
836 unsafe { SERVDB = Sys::open(c"/etc/services".into(), O_RDONLY, 0).or_minus_one_errno() }
837 } else {
838 if Sys::lseek(unsafe { SERVDB }, 0, SEEK_SET).is_ok() {}; unsafe { S_POS = 0 };
840 }
841}
842
843#[unsafe(no_mangle)]
845pub unsafe extern "C" fn getaddrinfo(
846 node: *const c_char,
847 service: *const c_char,
848 hints: *const addrinfo,
849 res: *mut *mut addrinfo,
850) -> c_int {
851 let node_opt = unsafe { CStr::from_nullable_ptr(node) };
852 let service_opt = unsafe { CStr::from_nullable_ptr(service) };
853
854 let hints_opt = if hints.is_null() {
855 None
856 } else {
857 Some(unsafe { &*hints })
858 };
859
860 log::trace!(
861 "getaddrinfo({:?}, {:?}, {:?})",
862 node_opt.map(|c| unsafe { str::from_utf8_unchecked(c.to_bytes()) }),
863 service_opt.map(|c| unsafe { str::from_utf8_unchecked(c.to_bytes()) }),
864 hints_opt
865 );
866
867 let mut ai_flags = hints_opt.map_or(0, |hints| hints.ai_flags);
869 let mut ai_family; let ai_socktype = hints_opt.map_or(0, |hints| hints.ai_socktype);
871 let mut ai_protocol; unsafe { *res = ptr::null_mut() };
874
875 let mut port = 0;
876 if let Some(service) = service_opt {
877 match unsafe { str::from_utf8_unchecked(service.to_bytes()) }.parse::<u16>() {
879 Ok(ok) => port = ok,
880 Err(_err) => (),
881 }
882 }
883 let node = node_opt.unwrap_or_else(|| {
884 if ai_flags & AI_PASSIVE > 0 {
886 c"0.0.0.0".into()
887 } else {
888 c"127.0.0.1".into()
889 }
890 });
891
892 let lookuphost = if ai_flags & AI_NUMERICHOST > 0 {
893 match parse_ipv4_string(unsafe { str::from_utf8_unchecked(node.to_bytes()) }) {
894 Some(s_addr) => vec![in_addr { s_addr }],
895 None => {
896 return EAI_NONAME;
897 }
898 }
899 } else {
900 match lookup_host(unsafe { str::from_utf8_unchecked(node.to_bytes()) }) {
901 Ok(lookuphost) => lookuphost,
902 Err(e) => {
903 platform::ERRNO.set(e);
904 return EAI_SYSTEM;
905 }
906 }
907 };
908
909 for in_addr in lookuphost {
910 ai_family = AF_INET;
911 ai_protocol = 0;
912
913 let ai_addr = Box::into_raw(Box::new(sockaddr_in {
914 sin_family: ai_family as sa_family_t,
915 sin_port: htons(port),
916 sin_addr: in_addr,
917 sin_zero: [0; 8],
918 }))
919 .cast::<sockaddr>();
920
921 let ai_addrlen = mem::size_of::<sockaddr_in>() as socklen_t;
922
923 let ai_canonname = if ai_flags & AI_CANONNAME > 0 {
924 if node_opt.is_none() {
925 return EAI_BADFLAGS;
926 }
927 ai_flags &= !AI_CANONNAME;
928 node.to_owned_cstring().into_raw()
929 } else {
930 ptr::null_mut()
931 };
932
933 let addrinfo = Box::new(addrinfo {
934 ai_flags: 0,
935 ai_family,
936 ai_socktype,
937 ai_protocol,
938 ai_addrlen,
939 ai_canonname,
940 ai_addr,
941 ai_next: ptr::null_mut(),
942 });
943 unsafe {
944 let mut indirect = res;
945 while !(*indirect).is_null() {
946 indirect = &raw mut (**indirect).ai_next;
947 }
948 *indirect = Box::into_raw(addrinfo)
949 }
950 }
951
952 0
953}
954
955#[unsafe(no_mangle)]
957pub unsafe extern "C" fn getnameinfo(
958 addr: *const sockaddr,
959 addrlen: socklen_t,
960 host: *mut c_char,
961 hostlen: socklen_t,
962 serv: *mut c_char,
963 servlen: socklen_t,
964 flags: c_int,
965) -> c_int {
966 if addr.is_null() || addrlen as usize != mem::size_of::<sockaddr_in>() {
967 return EAI_FAMILY;
968 }
969
970 let sa = unsafe { &*(addr.cast::<sockaddr_in>()) };
971
972 if !serv.is_null() && servlen > 0 {
973 if flags & NI_NUMERICSERV != 0 {
974 let port_str = sa.sin_port.to_be().to_string();
975 let port_bytes = port_str.as_bytes();
976 if (servlen as usize) <= port_bytes.len() {
977 return EAI_MEMORY; }
979 unsafe {
980 ptr::copy_nonoverlapping(
981 port_bytes.as_ptr().cast::<c_char>(),
982 serv,
983 port_bytes.len(),
984 )
985 };
986 unsafe { *serv.add(port_bytes.len()) = 0 };
987 } else {
988 unsafe { *serv = 0 };
990 }
991 }
992
993 if !host.is_null() && hostlen > 0 {
994 if flags & NI_NUMERICHOST != 0 {
995 let ip_addr = Ipv4Addr::from(sa.sin_addr.s_addr.to_be());
996 let ip_str = ip_addr.to_string();
997 let ip_bytes = ip_str.as_bytes();
998 if (hostlen as usize) <= ip_bytes.len() {
999 return EAI_MEMORY; }
1001 unsafe {
1002 ptr::copy_nonoverlapping(ip_bytes.as_ptr().cast::<c_char>(), host, ip_bytes.len())
1003 };
1004 unsafe { *host.add(ip_bytes.len()) = 0 };
1005 } else {
1006 match lookup_addr(sa.sin_addr.clone()).map(|host_names| host_names.into_iter().next()) {
1007 Ok(Some(hostname)) => {
1008 if (hostlen as usize) <= hostname.len() {
1009 return EAI_MEMORY; }
1011 unsafe {
1012 ptr::copy_nonoverlapping(
1013 hostname.as_ptr().cast::<c_char>(),
1014 host,
1015 hostname.len(),
1016 );
1017 *host.add(hostname.len()) = 0;
1018 }
1019 }
1020 Ok(None) => {
1021 if flags & NI_NAMEREQD != 0 {
1022 return EAI_NONAME;
1023 }
1024 }
1025 Err(_) => {
1026 if flags & NI_NAMEREQD != 0 {
1027 return EAI_NONAME;
1028 }
1029 let ip_addr = Ipv4Addr::from(sa.sin_addr.s_addr.to_be());
1030 let ip_str = ip_addr.to_string();
1031 let ip_bytes = ip_str.as_bytes();
1032 if (hostlen as usize) <= ip_bytes.len() {
1033 return EAI_MEMORY;
1034 }
1035 unsafe {
1036 ptr::copy_nonoverlapping(
1037 ip_bytes.as_ptr().cast::<c_char>(),
1038 host,
1039 ip_bytes.len(),
1040 );
1041 *host.add(ip_bytes.len()) = 0;
1042 }
1043 }
1044 }
1045 }
1046 }
1047
1048 0
1049}
1050
1051#[unsafe(no_mangle)]
1053pub unsafe extern "C" fn freeaddrinfo(res: *mut addrinfo) {
1054 let mut ai = res;
1055 while !ai.is_null() {
1056 let bai = unsafe { Box::from_raw(ai) };
1057 if !bai.ai_canonname.is_null() {
1058 drop(unsafe { CString::from_raw(bai.ai_canonname) });
1059 }
1060 if !bai.ai_addr.is_null() {
1061 if bai.ai_addrlen == mem::size_of::<sockaddr_in>() as socklen_t {
1062 unsafe { drop(Box::from_raw(bai.ai_addr.cast::<sockaddr_in>())) };
1063 } else if bai.ai_addrlen == mem::size_of::<sockaddr_in6>() as socklen_t {
1064 unsafe { drop(Box::from_raw(bai.ai_addr.cast::<sockaddr_in6>())) };
1065 } else {
1066 todo_skip!(0, "freeaddrinfo: unknown ai_addrlen {}", bai.ai_addrlen);
1067 }
1068 }
1069 ai = bai.ai_next;
1070 }
1071}
1072
1073#[unsafe(no_mangle)]
1075pub const extern "C" fn gai_strerror(errcode: c_int) -> *const c_char {
1076 match errcode {
1077 EAI_BADFLAGS => c"Invalid flags",
1078 EAI_NONAME => c"Name does not resolve",
1079 EAI_AGAIN => c"Try again",
1080 EAI_FAIL => c"Non-recoverable error",
1081 EAI_NODATA => c"Unknown error",
1082 EAI_FAMILY => c"Unrecognized address family or invalid length",
1083 EAI_SOCKTYPE => c"Unrecognized socket type",
1084 EAI_SERVICE => c"Unrecognized service",
1085 EAI_ADDRFAMILY => c"Address family for name not supported",
1086 EAI_MEMORY => c"Out of memory",
1087 EAI_SYSTEM => c"System error",
1088 EAI_OVERFLOW => c"Overflow",
1089 _ => c"Unknown error",
1090 }
1091 .as_ptr()
1092}
1093
1094#[unsafe(no_mangle)]
1096#[deprecated]
1097pub extern "C" fn __h_errno_location() -> *mut c_int {
1098 H_ERRNO.as_ptr()
1099}
1100
1101#[unsafe(no_mangle)]
1102#[deprecated]
1103pub const extern "C" fn hstrerror(errcode: c_int) -> *const c_char {
1104 match errcode {
1105 H_UNSET => c"Resolver error unset",
1106 HOST_NOT_FOUND => c"Unknown hostname",
1107 NO_DATA => c"No address for hostname",
1108 NO_RECOVERY => c"Unknown server error",
1109 TRY_AGAIN => c"Hostname lookup failure",
1110 _ => c"Unknown error",
1111 }
1112 .as_ptr()
1113}
1114
1115#[allow(clippy::not_unsafe_ptr_arg_deref)]
1130#[unsafe(no_mangle)]
1131#[deprecated]
1132pub extern "C" fn herror(prefix: *const c_char) {
1133 let code = H_ERRNO.get();
1134 let error = unsafe {
1136 #[allow(deprecated)]
1137 let msg_cstr = CStr::from_ptr(hstrerror(code));
1138 str::from_utf8_unchecked(msg_cstr.to_bytes())
1139 };
1140
1141 let mut writer = platform::FileWriter::new(2);
1142 match unsafe { CStr::from_nullable_ptr(prefix) }
1144 .and_then(|prefix| str::from_utf8(prefix.to_bytes()).ok())
1145 {
1146 Some(prefix) if !prefix.is_empty() => writer
1147 .write_fmt(format_args!("{prefix}: {error}\n"))
1148 .unwrap(),
1149 _ => writer.write_fmt(format_args!("{error}\n")).unwrap(),
1150 }
1151}