Commit e6a79d7b authored by Jeremy Soller's avatar Jeremy Soller

Initial commit

parents
The MIT License (MIT)
Copyright (c) 2016 Jeremy Soller
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# netutils
#[repr(packed)]
pub struct Dhcp {
pub op: u8,
pub htype: u8,
pub hlen: u8,
pub hops: u8,
pub tid: u32,
pub secs: u16,
pub flags: u16,
pub ciaddr: [u8; 4],
pub yiaddr: [u8; 4],
pub siaddr: [u8; 4],
pub giaddr: [u8; 4],
pub chaddr: [u8; 16],
pub sname: [u8; 64],
pub file: [u8; 128],
pub magic: u32,
pub options: [u8; 308]
}
use std::fs::File;
use std::io::{Read, Write};
use std::time;
use dhcp::Dhcp;
mod dhcp;
fn main(){
let mut current_mac = [0; 6];
File::open("netcfg:mac").unwrap().read(&mut current_mac).unwrap();
{
let mut current_ip = [0; 4];
File::open("netcfg:ip").unwrap().read(&mut current_ip).unwrap();
println!("DHCP: Current IP: {:?}", current_ip);
}
let tid = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().subsec_nanos();
let mut socket = File::open("udp:255.255.255.255:67/68").unwrap();
{
let mut discover = Dhcp {
op: 1,
htype: 1,
hlen: 6,
hops: 0,
tid: tid,
secs: 0,
flags: 0x8000u16.to_be(),
ciaddr: [0, 0, 0, 0],
yiaddr: [0, 0, 0, 0],
siaddr: [0, 0, 0, 0],
giaddr: [0, 0, 0, 0],
chaddr: [current_mac[0], current_mac[1], current_mac[2], current_mac[3], current_mac[4], current_mac[5],
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
sname: [0; 64],
file: [0; 128],
magic: 0x63825363u32.to_be(),
options: [0; 308]
};
for (s, mut d) in [53, 1, 1, 255].iter().zip(discover.options.iter_mut()) {
*d = *s;
}
let discover_data = unsafe { std::slice::from_raw_parts((&discover as *const Dhcp) as *const u8, std::mem::size_of::<Dhcp>()) };
let _sent = socket.write(discover_data).unwrap();
println!("DHCP: Sent Discover");
}
let mut offer_data = [0; 65536];
socket.read(&mut offer_data).unwrap();
let offer = unsafe { &* (offer_data.as_ptr() as *const Dhcp) };
println!("DHCP: Offer IP: {:?}, Server IP: {:?}", offer.yiaddr, offer.siaddr);
{
let mut subnet_option = None;
let mut router_option = None;
let mut dns_option = None;
let mut options = offer.options.iter();
while let Some(option) = options.next() {
match *option {
0 => (),
255 => break,
_ => if let Some(len) = options.next() {
if *len as usize <= options.as_slice().len() {
let data = &options.as_slice()[.. *len as usize];
for _data_i in 0..*len {
options.next();
}
match *option {
1 => {
println!("DHCP: Subnet Mask: {:?}", data);
if data.len() == 4 && subnet_option.is_none() {
subnet_option = Some(Vec::from(data));
}
},
3 => {
println!("DHCP: Router: {:?}", data);
if data.len() == 4 && router_option.is_none() {
router_option = Some(Vec::from(data));
}
},
6 => {
println!("DHCP: Domain Name Server: {:?}", data);
if data.len() == 4 && dns_option.is_none() {
dns_option = Some(Vec::from(data));
}
},
51 => println!("DHCP: Lease Time: {:?}", data),
53 => println!("DHCP: Message Type: {:?}", data),
54 => println!("DHCP: Server ID: {:?}", data),
_ => println!("DHCP: {}: {:?}", option, data)
}
}
},
}
}
{
File::open("netcfg:ip").unwrap().write(&offer.yiaddr).unwrap();
let mut new_ip = [0; 4];
File::open("netcfg:ip").unwrap().read(&mut new_ip).unwrap();
println!("DHCP: New IP: {:?}", new_ip);
}
if let Some(subnet) = subnet_option {
File::open("netcfg:ip_subnet").unwrap().write(&subnet).unwrap();
let mut new_subnet = [0; 4];
File::open("netcfg:ip_subnet").unwrap().read(&mut new_subnet).unwrap();
println!("DHCP: New Subnet: {:?}", new_subnet);
}
if let Some(router) = router_option {
File::open("netcfg:ip_router").unwrap().write(&router).unwrap();
let mut new_router = [0; 4];
File::open("netcfg:ip_router").unwrap().read(&mut new_router).unwrap();
println!("DHCP: New Router: {:?}", new_router);
}
if let Some(dns) = dns_option {
File::open("netcfg:dns").unwrap().write(&dns).unwrap();
let mut new_dns = [0; 4];
File::open("netcfg:dns").unwrap().read(&mut new_dns).unwrap();
println!("DHCP: New DNS: {:?}", new_dns);
}
}
{
let mut request = Dhcp {
op: 1,
htype: 1,
hlen: 6,
hops: 0,
tid: tid,
secs: 0,
flags: 0,
ciaddr: [0; 4],
yiaddr: [0; 4],
siaddr: offer.siaddr,
giaddr: [0; 4],
chaddr: [current_mac[0], current_mac[1], current_mac[2], current_mac[3], current_mac[4], current_mac[5],
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
sname: [0; 64],
file: [0; 128],
magic: 0x63825363u32.to_be(),
options: [0; 308]
};
for (s, mut d) in [53, 1, 3, 50, 4, offer.yiaddr[0], offer.yiaddr[1], offer.yiaddr[2], offer.yiaddr[3], 255].iter().zip(request.options.iter_mut()) {
*d = *s;
}
let request_data = unsafe { std::slice::from_raw_parts((&request as *const Dhcp) as *const u8, std::mem::size_of::<Dhcp>()) };
let _sent = socket.write(request_data).unwrap();
println!("DHCP: Sent Request");
}
{
let mut ack_data = [0; 65536];
socket.read(&mut ack_data).unwrap();
let ack = unsafe { &* (ack_data.as_ptr() as *const Dhcp) };
println!("DHCP: Ack IP: {:?}, Server IP: {:?}", ack.yiaddr, ack.siaddr);
}
}
#[derive(Clone, Debug)]
pub struct DnsAnswer {
pub name: String,
pub a_type: u16,
pub a_class: u16,
pub ttl_a: u16,
pub ttl_b: u16,
pub data: Vec<u8>
}
pub use self::answer::DnsAnswer;
pub use self::query::DnsQuery;
mod answer;
mod query;
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Default)]
#[repr(packed)]
pub struct n16 {
inner: u16
}
impl n16 {
pub fn as_bytes(&self) -> &[u8] {
use std::slice;
unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
}
pub fn from_bytes(bytes: &[u8]) -> Self {
use std::slice;
n16 {
inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] }
}
}
}
impl From<u16> for n16 {
fn from(value: u16) -> Self {
n16 {
inner: value.to_be()
}
}
}
impl From<n16> for u16 {
fn from(value: n16) -> Self {
use std::u16;
u16::from_be(value.inner)
}
}
#[derive(Clone, Debug)]
pub struct Dns {
pub transaction_id: u16,
pub flags: u16,
pub queries: Vec<DnsQuery>,
pub answers: Vec<DnsAnswer>
}
impl Dns {
pub fn compile(&self) -> Vec<u8> {
let mut data = Vec::new();
macro_rules! push_u8 {
($value:expr) => {
data.push($value);
};
};
macro_rules! push_n16 {
($value:expr) => {
data.extend_from_slice(n16::from($value).as_bytes());
};
};
push_n16!(self.transaction_id);
push_n16!(self.flags);
push_n16!(self.queries.len() as u16);
push_n16!(self.answers.len() as u16);
push_n16!(0);
push_n16!(0);
for query in self.queries.iter() {
for part in query.name.split('.') {
push_u8!(part.len() as u8);
data.extend_from_slice(part.as_bytes());
}
push_u8!(0);
push_n16!(query.q_type);
push_n16!(query.q_class);
}
data
}
pub fn parse(data: &[u8]) -> Result<Self, String> {
let mut i = 0;
macro_rules! pop_u8 {
() => {
{
i += 1;
if i > data.len() {
return Err(format!("{}: {}: pop_u8", file!(), line!()));
}
data[i - 1]
}
};
};
macro_rules! pop_n16 {
() => {
{
i += 2;
if i > data.len() {
return Err(format!("{}: {}: pop_n16", file!(), line!()));
}
u16::from(n16::from_bytes(&data[i - 2 .. i]))
}
};
};
macro_rules! pop_data {
() => {
{
let mut data = Vec::new();
let data_len = pop_n16!();
for _data_i in 0..data_len {
data.push(pop_u8!());
}
data
}
};
};
macro_rules! pop_name {
() => {
{
let mut name = String::new();
loop {
let name_len = pop_u8!();
if name_len == 0 {
break;
}
if ! name.is_empty() {
name.push('.');
}
for _name_i in 0..name_len {
name.push(pop_u8!() as char);
}
}
name
}
};
};
let transaction_id = pop_n16!();
let flags = pop_n16!();
let queries_len = pop_n16!();
let answers_len = pop_n16!();
pop_n16!();
pop_n16!();
let mut queries = Vec::new();
for _query_i in 0..queries_len {
queries.push(DnsQuery {
name: pop_name!(),
q_type: pop_n16!(),
q_class: pop_n16!()
});
}
let mut answers = Vec::new();
for _answer_i in 0..answers_len {
let name_ind = 0b11000000;
let name_test = pop_u8!();
i -= 1;
answers.push(DnsAnswer {
name: if name_test & name_ind == name_ind {
let name_off = pop_n16!() - ((name_ind as u16) << 8);
let old_i = i;
i = name_off as usize;
let name = pop_name!();
i = old_i;
name
} else {
pop_name!()
},
a_type: pop_n16!(),
a_class: pop_n16!(),
ttl_a: pop_n16!(),
ttl_b: pop_n16!(),
data: pop_data!()
});
}
Ok(Dns {
transaction_id: transaction_id,
flags: flags,
queries: queries,
answers: answers,
})
}
}
#[derive(Clone, Debug)]
pub struct DnsQuery {
pub name: String,
pub q_type: u16,
pub q_class: u16
}
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::time;
use dns::{Dns, DnsQuery};
mod dns;
fn main(){
let mut dns = [0; 4];
File::open("netcfg:dns").unwrap().read(&mut dns).unwrap();
println!("DNS: Server: {:?}", dns);
let tid = (time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().subsec_nanos() >> 16) as u16;
let packet = Dns {
transaction_id: tid,
flags: 0x0100,
queries: vec![DnsQuery {
name: env::args().nth(1).unwrap_or("static.redox-os.org".to_string()),
q_type: 0x0001,
q_class: 0x0001,
}],
answers: vec![]
};
let packet_data = packet.compile();
let mut socket = File::open(&format!("udp:{}.{}.{}.{}:53", dns[0], dns[1], dns[2], dns[3])).unwrap();
let _sent = socket.write(&packet_data).unwrap();
socket.flush().unwrap();
let mut buf = [0; 65536];
let count = socket.read(&mut buf).unwrap();
match Dns::parse(&buf[.. count]) {
Ok(response) => for answer in response.answers.iter() {
println!("DNS {} {:?}", count, answer.data);
},
Err(err) => {
println!("DNS {} {}", count, err);
}
}
}
use std::env;
use std::io::{stderr, Read, Write};
use std::net::TcpStream;
use std::process;
use std::str;
fn main() {
if let Some(url) = env::args().nth(1) {
let (scheme, reference) = url.split_at(url.find(':').unwrap_or(0));
if scheme == "http" {
let mut parts = reference.split('/').skip(2); //skip first two slashes
let remote = parts.next().unwrap_or("");
let mut path = parts.next().unwrap_or("").to_string();
for part in parts {
path.push('/');
path.push_str(part);
}
write!(stderr(), "* Connecting to {}\n", remote).unwrap();
let mut stream = TcpStream::connect(&remote).unwrap();
write!(stderr(), "* Requesting {}\n", path).unwrap();
let request = format!("GET /{} HTTP/1.1\r\nHost: {}\r\n\r\n", path, env::args().nth(2).unwrap_or(remote.to_string()));
stream.write(request.as_bytes()).unwrap();
stream.flush().unwrap();
write!(stderr(), "* Waiting for response\n").unwrap();
let mut response = [0; 65536];
let count = stream.read(&mut response).unwrap();
let mut headers = true;
for line in unsafe { str::from_utf8_unchecked(&response[.. count]) }.lines() {
if headers {
if line.is_empty() {
headers = false;
} else {
write!(stderr(), "> {}\n", line).unwrap();
}
} else {
println!("{}", line);
}
}
} else {
write!(stderr(), "wget: unknown scheme '{}'\n", scheme).unwrap();
process::exit(1);
}
} else {
write!(stderr(), "wget: http://host:port/path\n").unwrap();
process::exit(1);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment