• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 use crate::dns_https_frontend::DohFrontend;
18 use crate::stats::Stats;
19 
20 use anyhow::{bail, Result};
21 use libc::c_char;
22 use log::warn;
23 use std::ffi::CStr;
24 use std::net::{IpAddr, SocketAddr};
25 use std::str::FromStr;
26 
27 /// Creates a DohFrontend object by the given IP addresss and ports. Returns the pointer of
28 /// the object if the creation succeeds; otherwise, returns a null pointer.
29 ///
30 /// # Safety
31 ///
32 /// The parameters `addr`, `port`, `backend_addr`, and `backend_port` must all point to null
33 /// terminated UTF-8 encoded strings.
34 #[no_mangle]
frontend_new( addr: *const c_char, port: *const c_char, backend_addr: *const c_char, backend_port: *const c_char, ) -> *mut DohFrontend35 pub unsafe extern "C" fn frontend_new(
36     addr: *const c_char,
37     port: *const c_char,
38     backend_addr: *const c_char,
39     backend_port: *const c_char,
40 ) -> *mut DohFrontend {
41     let addr = CStr::from_ptr(addr).to_str().unwrap();
42     let port = CStr::from_ptr(port).to_str().unwrap();
43     let backend_addr = CStr::from_ptr(backend_addr).to_str().unwrap();
44     let backend_port = CStr::from_ptr(backend_port).to_str().unwrap();
45 
46     let socket_addr = to_socket_addr(addr, port).or_else(logging_and_return_err);
47     let backend_socket_addr =
48         to_socket_addr(backend_addr, backend_port).or_else(logging_and_return_err);
49     if socket_addr.is_err() || backend_socket_addr.is_err() {
50         return std::ptr::null_mut();
51     }
52 
53     match DohFrontend::new(socket_addr.unwrap(), backend_socket_addr.unwrap()) {
54         Ok(c) => Box::into_raw(c),
55         Err(_) => std::ptr::null_mut(),
56     }
57 }
58 
59 /// Starts the `DohFrontend` worker thread. Returns true if the worker thread is spawned
60 /// successfully; otherwise, it returns false.
61 #[no_mangle]
frontend_start(doh: &mut DohFrontend) -> bool62 pub extern "C" fn frontend_start(doh: &mut DohFrontend) -> bool {
63     doh.start().or_else(logging_and_return_err).is_ok()
64 }
65 
66 /// Stops the `DohFrontend` worker thread.
67 #[no_mangle]
frontend_stop(doh: &mut DohFrontend) -> bool68 pub extern "C" fn frontend_stop(doh: &mut DohFrontend) -> bool {
69     doh.stop().or_else(logging_and_return_err).is_ok()
70 }
71 
72 /// Deletes the `DohFrontend` created from `frontend_new`.
73 /// If the caller has called `frontend_start` to start `DohFrontend`, it has to call
74 /// call `frontend_stop` to stop the worker thread before deleting the object.
75 ///
76 /// # Safety
77 ///
78 /// The DohFrontend is not set to null pointer, caller needs to do it on its own.
79 #[no_mangle]
frontend_delete(doh: *mut DohFrontend)80 pub unsafe extern "C" fn frontend_delete(doh: *mut DohFrontend) {
81     if !doh.is_null() {
82         Box::from_raw(doh);
83     }
84 }
85 
86 /// Sets server certificate to `DohFrontend`.
87 ///
88 /// # Safety
89 ///
90 /// The given certificate must be a null-terminated UTF-8 encoded string.
91 #[no_mangle]
frontend_set_certificate( doh: &mut DohFrontend, certificate: *const c_char, ) -> bool92 pub unsafe extern "C" fn frontend_set_certificate(
93     doh: &mut DohFrontend,
94     certificate: *const c_char,
95 ) -> bool {
96     if certificate.is_null() {
97         return false;
98     }
99     let certificate = CStr::from_ptr(certificate).to_str().unwrap();
100     doh.set_certificate(certificate).or_else(logging_and_return_err).is_ok()
101 }
102 
103 /// Sets server private key to `DohFrontend`.
104 ///
105 /// # Safety
106 ///
107 /// The given private key must be a null-terminated UTF-8 encoded string.
108 #[no_mangle]
frontend_set_private_key( doh: &mut DohFrontend, private_key: *const c_char, ) -> bool109 pub unsafe extern "C" fn frontend_set_private_key(
110     doh: &mut DohFrontend,
111     private_key: *const c_char,
112 ) -> bool {
113     if private_key.is_null() {
114         return false;
115     }
116     let private_key = CStr::from_ptr(private_key).to_str().unwrap();
117     doh.set_private_key(private_key).or_else(logging_and_return_err).is_ok()
118 }
119 
120 /// Configures the `DohFrontend` not to process DoH queries until a given number of DoH queries
121 /// are received. This function works even in the middle of the worker thread.
122 #[no_mangle]
frontend_set_delay_queries(doh: &mut DohFrontend, count: i32) -> bool123 pub extern "C" fn frontend_set_delay_queries(doh: &mut DohFrontend, count: i32) -> bool {
124     doh.set_delay_queries(count).or_else(logging_and_return_err).is_ok()
125 }
126 
127 /// Configures the `DohFrontend` to use the given value for max_idle_timeout transport parameter.
128 #[no_mangle]
frontend_set_max_idle_timeout(doh: &mut DohFrontend, value: u64) -> bool129 pub extern "C" fn frontend_set_max_idle_timeout(doh: &mut DohFrontend, value: u64) -> bool {
130     doh.set_max_idle_timeout(value).or_else(logging_and_return_err).is_ok()
131 }
132 
133 /// Configures the `DohFrontend` to use the given value for these transport parameters.
134 /// - initial_max_data
135 /// - initial_max_stream_data_bidi_local
136 /// - initial_max_stream_data_bidi_remote
137 /// - initial_max_stream_data_uni
138 #[no_mangle]
frontend_set_max_buffer_size(doh: &mut DohFrontend, value: u64) -> bool139 pub extern "C" fn frontend_set_max_buffer_size(doh: &mut DohFrontend, value: u64) -> bool {
140     doh.set_max_buffer_size(value).or_else(logging_and_return_err).is_ok()
141 }
142 
143 /// Configures the `DohFrontend` to use the given value for initial_max_streams_bidi transport
144 /// parameter.
145 #[no_mangle]
frontend_set_max_streams_bidi(doh: &mut DohFrontend, value: u64) -> bool146 pub extern "C" fn frontend_set_max_streams_bidi(doh: &mut DohFrontend, value: u64) -> bool {
147     doh.set_max_streams_bidi(value).or_else(logging_and_return_err).is_ok()
148 }
149 
150 /// Sets the `DohFrontend` to block or unblock sending any data.
151 #[no_mangle]
frontend_block_sending(doh: &mut DohFrontend, block: bool) -> bool152 pub extern "C" fn frontend_block_sending(doh: &mut DohFrontend, block: bool) -> bool {
153     doh.block_sending(block).or_else(logging_and_return_err).is_ok()
154 }
155 
156 /// Gets the statistics of the `DohFrontend` and writes the result to |out|.
157 #[no_mangle]
frontend_stats(doh: &mut DohFrontend, out: &mut Stats) -> bool158 pub extern "C" fn frontend_stats(doh: &mut DohFrontend, out: &mut Stats) -> bool {
159     doh.request_stats()
160         .map(|stats| {
161             out.queries_received = stats.queries_received;
162             out.connections_accepted = stats.connections_accepted;
163             out.alive_connections = stats.alive_connections;
164             out.resumed_connections = stats.resumed_connections;
165         })
166         .or_else(logging_and_return_err)
167         .is_ok()
168 }
169 
170 /// Resets `queries_received` field of `Stats` owned by the `DohFrontend`.
171 #[no_mangle]
frontend_stats_clear_queries(doh: &DohFrontend) -> bool172 pub extern "C" fn frontend_stats_clear_queries(doh: &DohFrontend) -> bool {
173     doh.stats_clear_queries().or_else(logging_and_return_err).is_ok()
174 }
175 
176 /// Enable Rust debug logging.
177 #[no_mangle]
init_android_logger()178 pub extern "C" fn init_android_logger() {
179     android_logger::init_once(
180         android_logger::Config::default().with_tag("DohFrontend").with_min_level(log::Level::Debug),
181     );
182 }
183 
to_socket_addr(addr: &str, port: &str) -> Result<SocketAddr>184 fn to_socket_addr(addr: &str, port: &str) -> Result<SocketAddr> {
185     let socket_addr = SocketAddr::new(IpAddr::from_str(addr)?, port.parse()?);
186     Ok(socket_addr)
187 }
188 
logging_and_return_err<T, U: std::fmt::Debug>(e: U) -> Result<T>189 fn logging_and_return_err<T, U: std::fmt::Debug>(e: U) -> Result<T> {
190     warn!("logging_and_return_err: {:?}", e);
191     bail!("{:?}", e)
192 }
193