Commit 2c3f7f20 authored by Nawasan Wisitsingkhon's avatar Nawasan Wisitsingkhon

save state

parent 9de005e8
[package]
name = "tenjin"
version = "0.1.0"
edition = "2021"
[lib]
name = "tenjin"
path = "src/lib.rs"
[[bin]]
name = "tenjin"
path = "src/main.rs"
[dependencies]
[package]
name = "tenjin"
version = "0.1.0"
edition = "2021"
[lib]
name = "tenjin"
path = "src/lib.rs"
[[bin]]
name = "tenjin"
path = "src/main.rs"
[dependencies]
byteorder = "1.0.0"
\ No newline at end of file
This diff is collapsed.
# Tenjin SDN
## Goals
To understand The software-defined networking well, I trying to create a simple SDN with Rust language to support Openflow 1.0 first and 1.3 later.
## TODOs
- [ ] design structure of code and working.
# Tenjin SDN
## Goals
To understand The software-defined networking well, I trying to create a simple SDN with Rust language to support Openflow 1.0 first and 1.3 later.
## TODOs
- [ ] design structure of code and working.
- [ ] write more description in README.
\ No newline at end of file
pub enum EtherType {
IP = 0x0800,
ARP = 0x0806,
TEB = 0x6558,
VLAN = 0x8100,
IPV6 = 0x86dd,
SLOW = 0x8809,
MPLS = 0x8847,
SVLAN = 0x88a8,
LLDP = 0x88cc,
PBB = 0x88e7,
IEEE802_3 = 0x05dc,
CFM = 0x8902,
NSH = 0x894f,
}
use crate::etherparser::ether_type::EtherType;
use std::io::{BufRead, Cursor};
use byteorder::{BigEndian, ReadBytesExt};
use super::packet::IP;
struct EthernetFrame {
mac_des: u64,
mac_src: u64,
vlan: Option<u16>,
vlan_pcp: u8,
valn_dei: bool,
vlan_vid: u16,
}
impl EthernetFrame {
fn parse(payload: &Vec<u8>) {
let mut bytes = Cursor::new(*payload);
let mut mac_des = vec![0u8; 6];
let mut mac_src = vec![0u8; 6];
for i in 0..6 {
mac_des[i] = bytes.read_u8().unwrap();
}
for i in 0..6 {
mac_src[i] = bytes.read_u8().unwrap();
}
// check 802.1q tag tpid
let typ = bytes.read_u16::<BigEndian>().unwrap();
let (pcp, dei, vid, typ) = match typ {
tp if tp == EtherType::VLAN as u16 => {
let tci = bytes.read_u16::<BigEndian>().unwrap();
let pcp = tci >> 13;
let dei = (tci & 0x1000) > 0;
let vid = tci & 0xfff;
(pcp as u8, dei, Some(vid), typ)
}
_ => (0x0, false, None, typ),
};
let ip_header = match typ {
tp if tp == EtherType::IP as u16 => {
let ip = IP::parse(&mut bytes);
if ip.is_some() {
Network::IP(ip.unwrap())
} else {
Network::Unparsable(typ, bytes.fill_buf().unwrap().to_vec())
}
}
// tp if tp == (EtherType::ARP as u16) => {
// }
_ => Network::Unparsable(typ, bytes.fill_buf().unwrap().to_vec()),
};
}
}
pub enum Network {
IP(IP),
Unparsable(u16, Vec<u8>),
}
pub mod ether_type;
pub mod ethernet;
pub mod packet;
pub mod tools;
\ No newline at end of file
use std::io::{BufRead, Cursor};
use byteorder::{BigEndian, ReadBytesExt};
pub struct ICMP {
pub typ: u8,
pub code: u8,
pub checksum: u16,
pub payload: Vec<u8>,
}
impl ICMP {
pub fn size_of() -> usize {
4
}
pub fn parse(bytes: &mut Cursor<Vec<u8>>) -> Option<ICMP> {
if bytes.get_ref().len() < 4 {
return None;
}
let typ = bytes.read_u8().unwrap();
let code = bytes.read_u8().unwrap();
let checksum = bytes.read_u16::<BigEndian>().unwrap();
let payload = bytes.fill_buf().unwrap().to_vec();
Some(ICMP {
typ,
code,
checksum,
payload,
})
}
}
use super::{tcp::TCP, udp::UDP, ICMP};
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{BufRead, Cursor, Read};
struct Flags {
dont_flagment: bool,
more_fragments: bool,
}
pub struct IP {
pub version: u8,
pub ihl: u8,
pub tos: u8,
pub length: u16,
pub ident: u16,
pub flags: Flags,
pub fragment: u16,
pub ttl: u8,
pub protocol: u8,
pub checksum: u16,
pub src: u32,
pub des: u32,
pub options: Vec<u8>,
}
pub enum IpProtocol {
ICMP = 0x01,
TCP = 0x06,
UDP = 0x11,
}
impl IP {
pub fn parse(bytes: &mut Cursor<Vec<u8>>) -> Option<IP> {
if bytes.get_ref().len() < 20 {
return None;
}
let version_ihl = bytes.read_u8().unwrap();
let version = version_ihl >> 4;
if version != 4 {
return None;
}
let ihl = version_ihl & 0x0f;
let tos = bytes.read_u8().unwrap();
let length = bytes.read_u16::<BigEndian>().unwrap();
let ident = bytes.read_u16::<BigEndian>().unwrap();
let fragment = bytes.read_u16::<BigEndian>().unwrap();
let flags = Flags {
dont_flagment: (fragment & 0x8000) > 0,
more_fragments: (fragment >> 0x4000) > 0,
};
let ttl = bytes.read_u8().unwrap();
let protocol = bytes.read_u8().unwrap();
let checksum = bytes.read_u16::<BigEndian>().unwrap();
let src = bytes.read_u32::<BigEndian>().unwrap();
let des = bytes.read_u32::<BigEndian>().unwrap();
let option_len = (ihl * 4) as usize - 20;
let mut options = vec![0u8; option_len];
bytes.read_exact(&mut options).unwrap();
let ptcol = match protocol {
ptc if ptc == (IpProtocol::ICMP as u8) => {
let icmp = ICMP::parse(bytes);
match icmp {
Some(v) => EtherData::ICMP(v),
None => EtherData::Unparse(protocol, bytes.fill_buf().unwrap().to_vec()),
}
}
ptc if ptc == (IpProtocol::TCP as u8) => {
let tcp = TCP::parser(bytes);
if tcp.is_some() {
EtherData::TCP(tcp.unwrap())
} else {
EtherData::Unparse(protocol, bytes.fill_buf().unwrap().to_vec())
}
}
ptc if ptc == (IpProtocol::UDP as u8) => {
let udp = UDP::parser(bytes);
if udp.is_some() {
EtherData::UDP(udp.unwrap())
} else {
EtherData::Unparse(protocol, bytes.fill_buf().unwrap().to_vec())
}
}
_ => EtherData::Unparse(protocol, bytes.fill_buf().unwrap().to_vec()),
};
Some(IP {
version,
ihl,
length,
protocol,
tos,
ident,
flags,
fragment,
ttl,
checksum,
src,
des,
options,
})
}
}
pub enum EtherData {
ICMP(ICMP),
TCP(TCP),
UDP(UDP),
Unparse(u8, Vec<u8>),
}
pub mod icmp;
pub use icmp::ICMP;
pub mod tcp;
pub use tcp::TCP;
pub mod udp;
pub mod ipv4;
pub use ipv4::{IP, EtherData, IpProtocol};
\ No newline at end of file
use crate::etherparser::tools::bits::bit_bool;
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{BufRead, Cursor};
pub struct TCP {
pub src_port: u16,
pub des_port: u16,
pub seq: u32,
pub ack: u32,
pub offset: u8,
pub flags: TcpFlags,
pub window: u16,
pub checksum: u16,
pub urgent: u16,
pub payload: Vec<u8>,
}
impl TCP {
pub fn size_of() -> usize {
20
}
pub fn parser(bytes: &mut Cursor<Vec<u8>>) -> Option<TCP> {
if bytes.get_ref().len() < TCP::size_of() {
return None;
}
let src_port = bytes.read_u16::<BigEndian>().unwrap();
let des_port = bytes.read_u16::<BigEndian>().unwrap();
let seq = bytes.read_u32::<BigEndian>().unwrap();
let ack = bytes.read_u32::<BigEndian>().unwrap();
let dataoff_reserv_flags = bytes.read_u16::<BigEndian>().unwrap();
let flags = TcpFlags::parser(dataoff_reserv_flags);
let offset = (dataoff_reserv_flags >> 12) as u8 & 0x0f;
let window = bytes.read_u16::<BigEndian>().unwrap();
let checksum = bytes.read_u16::<BigEndian>().unwrap();
let urgent = bytes.read_u16::<BigEndian>().unwrap();
let payload = bytes.fill_buf().unwrap().to_vec();
Some(TCP {
src_port,
des_port,
seq,
ack,
offset,
flags,
window,
checksum,
urgent,
payload,
})
}
}
pub struct TcpFlags {
pub ns: bool,
pub cwr: bool,
pub ece: bool,
pub urg: bool,
pub ack: bool,
pub psh: bool,
pub rst: bool,
pub syn: bool,
pub fin: bool,
}
impl TcpFlags {
pub fn parser(bytes: u16) -> TcpFlags {
TcpFlags {
ns: bit_bool(0, bytes),
cwr: bit_bool(1, bytes),
ece: bit_bool(2, bytes),
urg: bit_bool(3, bytes),
ack: bit_bool(4, bytes),
psh: bit_bool(5, bytes),
rst: bit_bool(6, bytes),
syn: bit_bool(7, bytes),
fin: bit_bool(8, bytes),
}
}
}
use std::io::{BufRead, Cursor};
use byteorder::{BigEndian, ReadBytesExt};
pub struct UDP {
pub src_port: u16,
pub des_port: u16,
pub checksum: u16,
pub payload: Vec<u8>,
}
impl UDP {
pub fn sizeof() -> usize {
8
}
pub fn parser(bytes: &mut Cursor<Vec<u8>>) -> Option<UDP> {
if bytes.get_ref().len() < UDP::sizeof() {
return None;
}
let src_port = bytes.read_u16::<BigEndian>().unwrap();
let des_port = bytes.read_u16::<BigEndian>().unwrap();
let checksum = bytes.read_u16::<BigEndian>().unwrap();
let payload = bytes.fill_buf().unwrap().to_vec();
Some(UDP {
src_port,
des_port,
checksum,
payload,
})
}
}
pub fn bit_bool(position: u16, byte: u16) -> bool {
(byte >> position) & 1 == 1
}
pub mod bits;
\ No newline at end of file
pub mod openflow;
\ No newline at end of file
pub mod openflow;
pub mod etherparser;
\ No newline at end of file
use tenjin::openflow::{Controller, Msg, OfpHeader};
use std::io::Read;
use std::net::TcpListener;
extern crate byteorder;
fn main() -> Result<(), std::io::Error> {
let controller = Controller::new(Controller::OFP_1_0);
let listener = TcpListener::bind(("127.0.0.1", 6633)).unwrap();
let mut buf = vec![0u8; 8];
for stream in listener.incoming() {
println!("{:?}", stream);
match stream {
Ok(mut stream) => {
// std::thread::spawn(move || {
println!("=================== connection =======================");
// after tcp is connected, it will send hello message
controller.hello(&mut stream);
// loop for receive data
loop {
// first receive with Openflow header 64 bit to buf
match stream.read(&mut buf) {
Ok(v) if v > 0 => {
let packet = OfpHeader::parse(&buf);
// length_payload is var to receive payload if the packet has
// and assign size by length
let length_payload = packet.size();
let mut payload = vec![0u8; length_payload];
stream.read(&mut payload)?;
let message = Msg::parse(packet.message, &payload);
match message {
// 0 is Hello message
Msg::Hello => {
// after get Hello, send fetureReq
controller.feture_req(packet.xid, &mut stream);
println!("Hello event");
}
Msg::PacketIn(b) => {
println!("PacketIn event");
}
_ => {
println!("others message");
}
}
}
Ok(_) | Err(_) => break,
}
}
println!("======================================================");
// });
}
Err(_) => {
// connection failed
panic!("Connection failed")
}
}
}
Ok(())
}
use tenjin::openflow::{Controller, Msg, OfpHeader};
use std::io::Read;
use std::net::TcpListener;
extern crate byteorder;
fn main() -> Result<(), std::io::Error> {
let controller = Controller::new(Controller::OFP_1_0);
let listener = TcpListener::bind(("127.0.0.1", 6633)).unwrap();
let mut buf = vec![0u8; 8];
for stream in listener.incoming() {
println!("{:?}", stream);
match stream {
Ok(mut stream) => {
// std::thread::spawn(move || {
println!("=================== connection =======================");
// after tcp is connected, it will send hello message
controller.hello(&mut stream);
// loop for receive data
loop {
// first receive with Openflow header 64 bit to buf
match stream.read(&mut buf) {
Ok(v) if v > 0 => {
let packet = OfpHeader::parse(&buf);
// length_payload is var to receive payload if the packet has
// and assign size by length
let length_payload = packet.size();
let mut payload = vec![0u8; length_payload];
stream.read(&mut payload)?;
let message = Msg::parse(packet.message, &payload);
match message {
// 0 is Hello message
Msg::Hello => {
// after get Hello, send fetureReq
controller.feture_req(packet.xid, &mut stream);
println!("Hello event");
}
Msg::PacketIn(b) => {
controller.packetIn(xid, &payload, &mut stream);
println!("PacketIn event");
}
_ => {
println!("others message");
}
}
}
Ok(_) | Err(_) => break,
}
}
println!("======================================================");
// });
}
Err(_) => {
// connection failed
panic!("Connection failed")
}
}
}
Ok(())
}
use std::{io::Write, mem::size_of, net::TcpStream};
use byteorder::{BigEndian, WriteBytesExt};
use super::OfpHeader;
pub struct Controller {
version: u8,
}
impl Controller {
pub const OFP_1_0: u8 = 1;
pub fn new(version: u8) -> Self {
Self { version }
}
pub fn hello(&self, stream: &mut TcpStream) {
let header = OfpHeader::new(self.version, 0, size_of::<OfpHeader>() as u16, 0);
let mut bytes: Vec<u8> = Vec::new();
header.marshal(&mut bytes);
stream.write_all(&bytes).unwrap();
}
pub fn feture_req(&self, xid: u32, stream: &mut TcpStream) {
let header = OfpHeader::new(self.version, 5, 8, xid);
let mut bytes: Vec<u8> = Vec::new();
header.marshal(&mut bytes);
stream.write_all(&bytes).unwrap();
}
pub fn send(&self, xid: u32, message: u8, payload: &Vec<u8>, stream: &mut TcpStream) {
let length = size_of::<OfpHeader>() + payload.len();
let header = OfpHeader::new(self.version, message, length as u16, xid);
let mut bytes: Vec<u8> = Vec::new();
header.marshal(&mut bytes);
stream.write_all(&bytes).unwrap();
}
}
use std::{io::Write, mem::size_of, net::TcpStream};
use byteorder::{BigEndian, WriteBytesExt};
use etherparse::SlicedPacket;
use super::OfpHeader;
pub struct Controller {
version: u8,
}
impl Controller {
pub const OFP_1_0: u8 = 1;
pub fn new(version: u8) -> Self {
Self { version }
}
pub fn hello(&self, stream: &mut TcpStream) {
let header = OfpHeader::new(self.version, 0, size_of::<OfpHeader>() as u16, 0);
let mut bytes: Vec<u8> = Vec::new();
header.marshal(&mut bytes);
stream.write_all(&bytes).unwrap();
}
pub fn feture_req(&self, xid: u32, stream: &mut TcpStream) {
let header = OfpHeader::new(self.version, 5, 8, xid);
let mut bytes: Vec<u8> = Vec::new();
header.marshal(&mut bytes);
stream.write_all(&bytes).unwrap();
}
pub fn packetIn(&self, xid: u32, payload: &Vec<u8>, stream: &mut TcpStream) {
match SlicedPacket::from_ethernet(&payload) {
Ok(value) => {
println!("vlan {:?}", value.vlan);
println!("net {:?}", value.net);
},
Err(_) => println!("Error"),
}
}
pub fn send(&self, xid: u32, message: u8, payload: &Vec<u8>, stream: &mut TcpStream) {
let length = size_of::<OfpHeader>() + payload.len();
let header = OfpHeader::new(self.version, message, length as u16, xid);
let mut bytes: Vec<u8> = Vec::new();
header.marshal(&mut bytes);
stream.write_all(&bytes).unwrap();
}
}
use std::{io::Cursor, mem::size_of};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
pub struct OfpHeader {
pub version: u8,
pub message: u8,
pub length: u16,
pub xid: u32,
}
impl OfpHeader {
pub fn size(&self) -> usize {
return self.length as usize - size_of::<OfpHeader>();
}
pub fn new(version: u8, message: u8, length: u16, xid: u32) -> Self {
Self {
version,
message,
length,
xid,
}
}
pub fn parse(buf: &Vec<u8>) -> Self {
let mut buf_cursor = Cursor::new(buf);
// split data from header
let version = buf_cursor.read_u8().unwrap();
let message = buf_cursor.read_u8().unwrap();
// size is size of packet
let length = buf_cursor.read_u16::<BigEndian>().unwrap();
let xid = buf_cursor.read_u32::<BigEndian>().unwrap();
Self {
version,
message,
length,
xid,
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) {
bytes.write_u8(self.version).unwrap();
bytes.write_u8(self.message).unwrap();
bytes.write_u16::<BigEndian>(self.length).unwrap();
bytes.write_u32::<BigEndian>(self.xid).unwrap();
}
}
use std::{io::Cursor, mem::size_of};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
pub struct OfpHeader {
pub version: u8,
pub message: u8,
pub length: u16,
pub xid: u32,
}
impl OfpHeader {
pub fn size(&self) -> usize {
return self.length as usize - size_of::<OfpHeader>();
}
pub fn new(version: u8, message: u8, length: u16, xid: u32) -> Self {
Self {
version,
message,
length,
xid,
}
}
pub fn parse(buf: &Vec<u8>) -> Self {
let mut buf_cursor = Cursor::new(buf);
// split data from header
let version = buf_cursor.read_u8().unwrap();
let message = buf_cursor.read_u8().unwrap();
// size is size of packet
let length = buf_cursor.read_u16::<BigEndian>().unwrap();
let xid = buf_cursor.read_u32::<BigEndian>().unwrap();
Self {
version,
message,
length,
xid,
}
}
pub fn marshal(&self, bytes: &mut Vec<u8>) {
bytes.write_u8(self.version).unwrap();
bytes.write_u8(self.message).unwrap();
bytes.write_u16::<BigEndian>(self.length).unwrap();
bytes.write_u32::<BigEndian>(self.xid).unwrap();
}
}
pub enum Msg {
Hello,
PacketIn(Vec<u8>),
NotFound,
}
impl Msg {
pub fn parse(message_code: u8, payload: &Vec<u8>) -> Self {
match message_code {
0 => Msg::Hello,
8 => Msg::PacketIn(payload.clone()),
_ => Msg::NotFound,
}
}
}
pub enum Msg {
Hello,
PacketIn(Vec<u8>),
NotFound,
}
impl Msg {
pub fn parse(message_code: u8, payload: &Vec<u8>) -> Self {
match message_code {
0 => Msg::Hello,
8 => Msg::PacketIn(payload.clone()),
_ => Msg::NotFound,
}
}
}
pub mod header;
pub use header::OfpHeader;
pub mod message;
pub use message::Msg;
pub mod controller;
pub use controller::Controller;
pub mod header;
pub use header::OfpHeader;
pub mod message;
pub use message::Msg;
pub mod controller;
pub use controller::Controller;
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