You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
10 KiB

  1. use async_std::net::{SocketAddr, ToSocketAddrs, UdpSocket};
  2. use std::error::Error;
  3. use std::net::Ipv4Addr;
  4. use std::convert::TryInto;
  5. use byteorder::{BigEndian, ByteOrder};
  6. use rand::Rng;
  7. use sha1::{Sha1, Digest};
  8. extern crate serde;
  9. extern crate serde_bencode;
  10. #[macro_use]
  11. extern crate serde_derive;
  12. extern crate serde_bytes;
  13. use serde_bencode::{de, ser};
  14. use serde_bytes::ByteBuf;
  15. // use rustc_hex::ToHex;
  16. const CONNECT_MSG: u32 = 0;
  17. const ANNOUNCE_MSG: u32 = 1;
  18. #[derive(Debug, Deserialize)]
  19. struct Node(String, i64);
  20. #[derive(Debug, Serialize, Deserialize)]
  21. struct File {
  22. path: Vec<String>,
  23. length: i64,
  24. #[serde(default)]
  25. md5sum: Option<String>,
  26. }
  27. #[derive(Debug, Serialize, Deserialize)]
  28. struct Info {
  29. name: String,
  30. pieces: ByteBuf,
  31. #[serde(rename = "piece length")]
  32. piece_length: i64,
  33. #[serde(default)]
  34. md5sum: Option<String>,
  35. #[serde(default)]
  36. length: Option<i64>,
  37. #[serde(default)]
  38. files: Option<Vec<File>>,
  39. #[serde(default)]
  40. private: Option<u8>,
  41. #[serde(default)]
  42. path: Option<Vec<String>>,
  43. #[serde(default)]
  44. #[serde(rename = "root hash")]
  45. root_hash: Option<String>,
  46. }
  47. #[derive(Debug, Deserialize)]
  48. struct Torrent {
  49. info: Info,
  50. #[serde(default)]
  51. announce: Option<String>,
  52. #[serde(default)]
  53. nodes: Option<Vec<Node>>,
  54. #[serde(default)]
  55. encoding: Option<String>,
  56. #[serde(default)]
  57. httpseeds: Option<Vec<String>>,
  58. #[serde(default)]
  59. #[serde(rename = "announce-list")]
  60. announce_list: Option<Vec<Vec<String>>>,
  61. #[serde(default)]
  62. #[serde(rename = "creation date")]
  63. creation_date: Option<i64>,
  64. #[serde(rename = "comment")]
  65. comment: Option<String>,
  66. #[serde(default)]
  67. #[serde(rename = "created by")]
  68. created_by: Option<String>,
  69. }
  70. impl Torrent {
  71. pub fn open(path: &str) -> Torrent {
  72. let b = std::fs::read(path).unwrap();
  73. de::from_bytes::<Torrent>(&b).unwrap()
  74. }
  75. pub fn size(&self) -> u64 {
  76. let files = self.info.files.as_ref().unwrap();
  77. let mut size: u64 = 0;
  78. for i in 0..files.len() {
  79. size = size + files[i].length as u64;
  80. }
  81. size
  82. }
  83. pub fn info_hash(&self) -> Vec<u8> {
  84. let info_bytes: Vec<u8> = ser::to_bytes(&self.info).unwrap();
  85. let mut hasher = Sha1::new();
  86. hasher.update(info_bytes);
  87. let result = hasher.finalize();
  88. result.to_vec()
  89. }
  90. pub fn announce(&self) -> Option<String> {
  91. let mut a: String = "".to_string();
  92. match &self.announce {
  93. Some(s) => {
  94. a = s.to_string();
  95. }
  96. _ => (),
  97. };
  98. match &self.announce_list { // TODO refactor approach
  99. Some(list) => {
  100. a = list[0][0].clone();
  101. }
  102. _ => (),
  103. };
  104. Some(a)
  105. }
  106. pub fn protocol(&self) -> Option<String> {
  107. let announce = &self.announce().unwrap();
  108. let aux: Vec<&str> = announce.split(":").collect();
  109. let protocol = aux[0];
  110. Some(protocol.to_string())
  111. }
  112. pub async fn get_peers(&self) -> Result<Vec<Peer>, Box<dyn Error>> {
  113. // TODO timming system to resend request if no answer in X seconds
  114. if self.protocol().unwrap() != "udp" {
  115. panic!("not udp: {:?}", self.protocol().unwrap());
  116. }
  117. let peer = self.announce.clone().unwrap().replace("udp://", "");
  118. println!("peer {:?}", peer);
  119. let socket = UdpSocket::bind("0.0.0.0:6681").await?;
  120. let conn_req = conn_req_msg().to_vec();
  121. println!("SENDING conn_req {:?}", conn_req);
  122. socket.send_to(&conn_req, &peer).await?;
  123. let mut buf = vec![0; 1024];
  124. let peers = loop {
  125. let (n, src) = socket.recv_from(&mut buf).await?;
  126. let typ = resp_type(&buf);
  127. if typ == CONNECT_MSG {
  128. println!("TYPE: CONNECT: {:?}", CONNECT_MSG);
  129. // println!("HEX {:?}", &buf[0..n].to_hex());
  130. let conn_resp = parse_connect_resp(&buf[0..n].to_vec());
  131. let announce_req = ann_req_msg(conn_resp.connection_id, self, 6681);
  132. socket.send_to(&announce_req[..], &src).await?;
  133. } else if typ==ANNOUNCE_MSG {
  134. println!("TYPE: ANNOUNCE: {:?}", ANNOUNCE_MSG);
  135. // println!("HEX {:?}", &buf[0..n].to_hex());
  136. let ann_resp = parse_announce_resp(&buf[0..n].to_vec());
  137. break ann_resp.peers;
  138. }
  139. };
  140. Ok(peers)
  141. }
  142. }
  143. fn conn_req_msg() -> [u8; 16] {
  144. let mut b: [u8; 16] = [0; 16];
  145. BigEndian::write_u64(&mut b[0..8], 0x41727101980); // connection_id
  146. let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
  147. b[12..16].clone_from_slice(&random_bytes[..]);
  148. b
  149. }
  150. fn ann_req_msg(connection_id: u64, torrent: &Torrent, port: u16) -> Vec<u8> {
  151. let mut b: [u8; 98] = [0; 98];
  152. BigEndian::write_u64(&mut b[0..8], connection_id);
  153. BigEndian::write_u32(&mut b[8..12], ANNOUNCE_MSG); // action
  154. let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
  155. b[12..16].clone_from_slice(&random_bytes[..]);
  156. b[16..36].clone_from_slice(&torrent.info_hash()[..]);
  157. println!("info_hash: {:?}", &b[16..36]);
  158. // TODO [36..56] peerId b[36..56].clone_from_slice("todo".as_bytes());
  159. // TODO [56..64] downloaded
  160. println!("torrent.size(): {:?}", torrent.size());
  161. BigEndian::write_u64(&mut b[64..72], torrent.size()); // [64..72] left
  162. // TODO [72..80] uploaded
  163. // TODO [80..84] event (0:none, 1:completed, 2:started, 3:stopped)
  164. // TODO [84..88] ip address
  165. let random_bytes = rand::thread_rng().gen::<[u8; 4]>();
  166. b[88..92].clone_from_slice(&random_bytes[..]); // [88..92] key (random)
  167. BigEndian::write_i32(&mut b[92..96], -1); // [92..96] num_want (default: -1)
  168. BigEndian::write_u16(&mut b[96..98], port); // [96..98] port
  169. b.to_vec()
  170. }
  171. fn resp_type(b: &Vec<u8>) -> u32 {
  172. let action = BigEndian::read_u32(&b[0..4]);
  173. if action == 0 {
  174. return CONNECT_MSG;
  175. } else {
  176. return ANNOUNCE_MSG;
  177. }
  178. }
  179. #[derive(Debug)]
  180. struct ConnResp {
  181. action: u32,
  182. transaction_id: u32,
  183. connection_id: u64,
  184. }
  185. fn parse_connect_resp(b: &Vec<u8>) -> ConnResp {
  186. ConnResp {
  187. action: BigEndian::read_u32(&b[0..4]),
  188. transaction_id: BigEndian::read_u32(&b[4..8]),
  189. connection_id: BigEndian::read_u64(&b[8..]),
  190. }
  191. }
  192. #[derive(Debug)]
  193. struct Peer {
  194. ip: String,
  195. port: u16
  196. }
  197. #[derive(Debug)]
  198. struct AnnResp {
  199. action: u32,
  200. transaction_id: u32,
  201. interval: u32,
  202. leechers: u32,
  203. seeders: u32,
  204. peers: Vec<Peer>,
  205. }
  206. fn parse_announce_resp(b: &Vec<u8>) -> AnnResp {
  207. let mut peers: Vec<Peer> = Vec::new();
  208. let n_peers = (b.len()-20)/6;
  209. for i in 0..n_peers {
  210. let peer: Peer = Peer {
  211. // ip: BigEndian::read_u32(&b[20+(6*i)..24+(6*i)]),
  212. ip: bytes_to_ip(&b[20+(6*i)..24+(6*i)].try_into().expect("err parsing peer ip")),
  213. port: BigEndian::read_u16(&b[24+(6*i)..26+(6*i)]),
  214. };
  215. peers.push(peer);
  216. }
  217. let ann_resp: AnnResp = AnnResp {
  218. action: BigEndian::read_u32(&b[0..4]),
  219. transaction_id: BigEndian::read_u32(&b[4..8]),
  220. interval: BigEndian::read_u32(&b[8..12]),
  221. leechers: BigEndian::read_u32(&b[12..16]),
  222. seeders: BigEndian::read_u32(&b[16..20]),
  223. peers: peers
  224. };
  225. ann_resp
  226. }
  227. fn bytes_to_ip(b: &[u8; 4]) -> String {
  228. Ipv4Addr::new(b[0], b[1], b[2], b[3]).to_string()
  229. }
  230. #[cfg(test)]
  231. mod tests {
  232. use super::*;
  233. use rustc_hex::ToHex;
  234. #[test]
  235. fn torrent_structs() {
  236. let t = Torrent::open("test.torrent");
  237. assert_eq!(t.info.name, "Big Buck Bunny");
  238. assert_eq!(t.announce().unwrap(), "udp://tracker.leechers-paradise.org:6969");
  239. assert_eq!(t.info_hash().to_hex(), "dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c");
  240. assert_eq!(t.size(), 276445467);
  241. }
  242. #[test]
  243. fn discovery_msgs() {
  244. let t = Torrent::open("test.torrent");
  245. let conn_req = conn_req_msg().to_vec();
  246. assert_eq!(conn_req[0..12].to_hex(), "000004172710198000000000"); // [12..16] is random
  247. let conn_resp_buf = b"00000000d4c575c2c078f9a83418bebc";
  248. let conn_resp = parse_connect_resp(&conn_resp_buf.to_vec());
  249. println!("conn_resp {:?}", conn_resp);
  250. assert_eq!(conn_resp.action, 808464432);
  251. assert_eq!(conn_resp.transaction_id, 808464432);
  252. assert_eq!(conn_resp.connection_id, 7220505182792409906);
  253. let announce_req = ann_req_msg(conn_resp.connection_id, &t, 6681);
  254. assert_eq!(announce_req[0..12].to_hex(), "643463353735633200000001");
  255. assert_eq!(announce_req[16..72].to_hex(), "dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c0000000000000000000000000000000000000000000000000000000000000000107a391b");
  256. assert_eq!(announce_req[92..98].to_hex(), "ffffffff1a19");
  257. let announce_resp_buf = b"000000017a638a60000006e8000000030000002429d412a11ae12d53dcbd1a19d048c0e51ae1d8241960c8d5d5c36e71c8d5c5b974a31ae2c11ef348d4aabc5f370ec8d5bc4e16321ae1b9cee13b2327b94187b66f7cb94186b1c8d5b75308331ae1b068c0e0c263ac6f857911389d27ac821ae19088c2c01ae172fe2468c00a699aebe6720f68a2f99a1ae167fce2141ae163582ee41ae1634921a5d2725b72aaf5c8d559482e8fc9d257fb394cc8d55740e9ebd166524044e11aff51b6dcb6c8d54e2ebe61c3574b87860fc8d54b6e11026dff473afc7a1ec944cd47cd1ae131249b051ae124ff6b521ae105b75c13c8d50551153a1ae105024e09cd52";
  258. let ann_resp = parse_announce_resp(&announce_resp_buf.to_vec());
  259. assert_eq!(ann_resp.peers.len(), 81);
  260. assert_eq!(ann_resp.peers[0].ip, "48.54.101.56");
  261. assert_eq!(ann_resp.peers[0].port, 12336);
  262. assert_eq!(ann_resp.peers[80].ip, "52.101.48.57");
  263. assert_eq!(ann_resp.peers[80].port, 25444);
  264. }
  265. #[async_std::test]
  266. async fn get_peers() {
  267. let t = Torrent::open("test.torrent");
  268. // println!("{:?}", t);
  269. println!("torrent: {:?}", t.info.name);
  270. println!("protocol: {:?}", t.protocol().unwrap());
  271. println!("conn_req_msg: {:?}", conn_req_msg());
  272. let r = t.get_peers().await;
  273. println!("get_peers r: {:?}", r);
  274. }
  275. }