308 lines
29 KiB
TeX
308 lines
29 KiB
TeX
%*******************************************************************************
|
|
%****************************** Second Chapter *********************************
|
|
%*******************************************************************************
|
|
|
|
\chapter{Preparation}
|
|
|
|
\ifpdf
|
|
\graphicspath{{Preparation/Figs/Raster/}{Preparation/Figs/PDF/}{Preparation/Figs/}}
|
|
\else
|
|
\graphicspath{{Preparation/Figs/Vector/}{Preparation/Figs/}}
|
|
\fi
|
|
|
|
Proxying packets is the process of taking packets arriving at one location and transporting them to leave at another. This chapter focuses on the preparatory work to achieve this correctly, given the design laid out in the previous chapter. In sections \ref{section:risk-analysis} to \ref{section:preparation-security}, I discuss the security risks and plans to confront them. In section \ref{section:language-selection}, I present three languages: Go, Rust and C++ - providing context for choosing Go as the implementation language. Finally, in sections \ref{section:requirements-analysis} and \ref{section:engineering-approach}, I present a requirements analysis and a description of the engineering approach for the project.
|
|
|
|
% ---------------------------- Risk Analysis ------------------------------- %
|
|
\section{Risk Analysis}
|
|
\label{section:risk-analysis}
|
|
|
|
Proxying a network connection via a Remote Portal creates an expanded set of security risks than connecting directly to the Internet via a modem. In this section, I will analyse these risks, in both isolation, and compared to the case of connecting directly.
|
|
|
|
Firstly, this analysis focuses on transparent security. This is the case of the Local Portal and Remote Portal, with everything in between, being collapsed into a special Internet connection. The focus is on how the risks compare to that of a standard Internet connection, and what guarantees must be made to reach the same set of risks.
|
|
|
|
Secondly, this section focuses on the connection between the Local Portal and the Remote Portal. This section focuses primarily on the risks of incorrectly validating authenticity of connections and packets.
|
|
|
|
These security problems will be considered in the context of the success criteria: provide security no worse than not using this solution at all. That is, the security should be identical or stronger than the threats in the first case, and provide no additional vectors of attack in the second.
|
|
|
|
\subsection{Transparent Security}
|
|
|
|
A convenient factor of the Internet being an interconnected set of smaller networks is that there are very few guarantees of security. At layer 3, none of anonymity, integrity, privacy or freshness are provided, so it is up to the application to ensure its own security on top of this lack of guarantees. For the purposes of this software, this is very useful: if there are no guarantees to maintain, applications can be expected to act correctly regardless of how easy it is for these cases to occur.
|
|
|
|
Therefore, to maintain the same level of security for applications, it is sufficient to guarantee that the set of packets which leave the Remote Portal is a subset of those that entered the Local Portal, and vice versa. In such a case, all of the security implemented above Layer 3 will be maintained. This means that whether a user is accessing insecure websites over HTTP, running a corporate VPN connection or sending encrypted emails, the security of these applications will be unaltered.
|
|
|
|
\subsection{Portal to Portal Communication}
|
|
|
|
\subsubsection{Cost}
|
|
|
|
Many Internet connections have limits or charges for bandwidth usage. In a standard network, the control of your cap is physical, in that, if someone wished to increase the load, they would have to physically connect to the modem.
|
|
|
|
Due to this, it is important that care is taken with regards to cost. So, rather than needing physical access, all one needs is Internet access to send data through your connection. A conceivable threat is for someone to send packets to your Remote Portal from their own connection, causing the Portal to forward these packets, and thus using your limited or costly bandwidth.
|
|
|
|
\subsubsection{Denial of Service}
|
|
\label{subsubsection:threats-denial-of-service}
|
|
|
|
\begin{figure}
|
|
\centering
|
|
\begin{subfigure}{.49\textwidth}
|
|
\begin{tabularx}{\textwidth}{ | p{0.4\textwidth}>{\raggedright\arraybackslash}X p{0.4\textwidth}>{\raggedright\arraybackslash}X | }
|
|
Downlink Capacity & Percentage of Packets \\
|
|
25 Mbps & 5\% \\
|
|
25 Mbps & 5\% \\
|
|
25 Mbps & 5\% \\
|
|
(BAD) 425 Mbps & 85\%
|
|
\end{tabularx}
|
|
\caption{A bad actor with a faster connection than you taking a percentage of packets.}
|
|
\label{fig:fast-bad-actor-packet-loss}
|
|
\end{subfigure}
|
|
\begin{subfigure}{.49\textwidth}
|
|
\begin{tabularx}{\textwidth}{ | p{0.4\textwidth}>{\raggedright\arraybackslash}X p{0.4\textwidth}>{\raggedright\arraybackslash}X | }
|
|
Downlink Capacity & Percentage of Packets \\
|
|
25 Mbps & 25\% \\
|
|
25 Mbps & 25\% \\
|
|
25 Mbps & 25\% \\
|
|
(BAD) 25 Mbps & 25\%
|
|
\end{tabularx}
|
|
\caption{A bad actor with an equally slow connection to you taking a percentage of packets.}
|
|
\label{fig:slow-bad-actor-packet-loss}
|
|
\end{subfigure}
|
|
\caption{Comparing the percentage of packets a bad actor can steal to their downlink capacity.}
|
|
\label{fig:bad-actor-packet-loss}
|
|
\end{figure}
|
|
|
|
If a malicious actor can fool the Remote Portal into sending them a portion of your packets, they are immediately performing an effective Denial of Service on any tunnelled flows relying on loss based congestion control. In figure \ref{fig:fast-bad-actor-packet-loss}, it can be seen that a bad actor, with a significantly faster connection than you, can cause huge packet loss if the Remote Portal would accept them as a valid Local Portal connection.
|
|
|
|
\begin{figure}
|
|
\begin{equation}
|
|
Throughput = \sqrt{\frac{3}{2}}\frac{1}{RTT\sqrt{p}}
|
|
\end{equation}
|
|
\caption{TCP Throughput Equation (New Reno)}
|
|
\label{fig:tcp-throughput}
|
|
\end{figure}
|
|
|
|
However, of much more relevance is \ref{fig:slow-bad-actor-packet-loss}. Given the TCP throughput equation, shown in figure \ref{fig:tcp-throughput}, there is an inverse relation between packet loss and throughput of any TCP connections. Assuming a Round Trip Time of $20ms$ and Maximum Segment Size of $1460$, packet loss of $25\%$ limits the maximum TCP throughput to approximately $1.17Mbps$. In fact, due to this relation, a packet loss of even $1\%$ leads to a maximum throughput of approximately $5.84Mbps$. This means that even a small packet loss can have a drastic effect on the performance of the connection as a whole, and thus makes Remote Portals an effective target for Denial of Service attacks. Care must be taken that all Local Portal connections are from the intended subject.
|
|
|
|
\subsection{Privacy}
|
|
|
|
Though the packets leaving a modem have no reasonable expectation of privacy, having the packets enter the Internet at two points does increase this vector. However, this is equivalent to your packets taking a longer route through the Internet, with more hops. Therefore, comparatively, this is not worse.
|
|
|
|
Further, if an attacker convinces the Remote Portal that they are a valid connection from the Local Portal, a portion of packets will be sent to them. However, as a fortunate side effect, this method to attempt sniffing would cause a significant Denial of Service to any congestion controlled links based on packet loss, due to the amount of packet loss caused. Therefore, as long as it is ensured that each packet is not sent to multiple places, privacy should be maintained at a similar level to simple Internet access.
|
|
|
|
% ----------------------------- Threat Model ------------------------------- %
|
|
\section{Threat Model}
|
|
\label{section:threat-model}
|
|
|
|
In this section, we discuss a set of threats that expose the risk discussed in section \ref{section:risk-analysis}.
|
|
|
|
\subsection{Stealing Packets}
|
|
|
|
This section focuses on an attacker that exploits the connection between the Local Portal and Remote Portal to prevent packets sent from one side arriving at the other. Recall, as stated in the Risk Analysis section, that this is high risk - taking packets causes significant packet loss and thus effectively denies service for loss based congestion control mechanisms.
|
|
|
|
Methods such as cutting cables, which would apply equally without this solution, are excluded. This solution prioritises resilience in such a case, and would lose less packets than either connection by themselves, so the risk is less than or equal to a solitary connection.
|
|
|
|
\subsubsection{Unauthenticated Flows}
|
|
|
|
If the flows provide no additional authentication, it is trivial for an attacker to create a flow of their own and connect.
|
|
|
|
\subsubsection{Reflection Attacks}
|
|
\label{section:reflection-attacks}
|
|
|
|
An attack vector for someone attempting to read but not write packets is a reflection attack. A reflection attack is an attack where an attacker is able to provide the challenge you have given either to the victim itself or a friend of the victim, to receive the correct challenge response \citep[pp. 76-78]{anderson_security_2008}.
|
|
|
|
\begin{align*}
|
|
A \longrightarrow M &: N \\
|
|
M \longrightarrow A &: N \\
|
|
A \longrightarrow M &: \{N\}_k \\
|
|
M \longrightarrow A &: \{N\}_k
|
|
\end{align*}
|
|
|
|
An attacker, $M$, can use a reflection attack to begin a flow with a shared key system. This would cause the far side, in the above exchange $A$, to trust $M$ for the remainder of their flow. $M$ would then receive a portion of the packets dispatched by $A$, as a function of $M$'s bandwidth over the total bandwidth of $A$'s receivers.
|
|
|
|
\subsection{Sending Fresh Packets}
|
|
|
|
These threats resolve around an actor sending packets of their own design to one of the servers, such that the server proxies it. Aimed at the Local Portal, this is a non-issue (anyone could achieve the same by simply sending a packet to the Remote Portal's public interface), so this will be focused on a bad actor sending packets outbound via the Remote Portal.
|
|
|
|
\subsubsection{Simple Packets with Unauthenticated Flows}
|
|
|
|
If packets are sent with no additional security data, using either TCP, UDP, or raw IP, it is trivial for a new attacker to create a flow and generate the correct structure to send their own packets.
|
|
|
|
\subsubsection{Simple Packets with Authenticated Flows}
|
|
|
|
If packets are sent with no additional security data, but the flows are authenticated, sending packets becomes more complex. However, the threat is still very much open - using a Man in the Middle attack and protocol knowledge, one can inject packets to an existing flow (Citation Needed).
|
|
|
|
\subsection{Replay Attacks}
|
|
|
|
An attacker having the ability to cause the Remote Portal to resend a packet relates to the Cost section of the Risk Analysis given above. As each packet forwarded has an essentially fixed cost, repeating these packets one or many times can cost the subject. This threat exists if a message does not successfully guarantee freshness.
|
|
|
|
\subsubsection{Man in the Middle}
|
|
|
|
This threat is based on an attacker wishing to force cost upon you. In the example layout given in figure \ref{fig:mitm-middlebox}, the middlebox can sniff the packets from anywhere on the path(s) between the Local Portal and the Remote Portal. In this case, the middlebox could increase the traffic leaving the remote portal by 100x at full load, or even more at less load, increasing the cost by also 100x.
|
|
|
|
\begin{figure}
|
|
\centering
|
|
\includegraphics[width=12cm]{Middlebox.png}
|
|
\caption{A middlebox placed to perform a repeating packet man in the middle attack between a local and remote portal}
|
|
\label{fig:mitm-middlebox}
|
|
\end{figure}
|
|
|
|
% ------------------------------- Security --------------------------------- %
|
|
\section{Security}
|
|
\label{section:preparation-security}
|
|
|
|
This section provides means of confronting the threats given in section \ref{section:threat-model}, in order to alleviate the additional risk of proxying traffic.
|
|
|
|
\subsection{Message Authentication}
|
|
|
|
To provide integrity and authentication for each message, I present two choices: a Hash-based Message Authentication Code (HMAC) or Digital Signatures. Producing a digital signature for a message uses the private key in public/private keypair to produce a digital signature for a message, stating that the message was produced by the owner of the private key, which can be verified by anyone with the public key \citep[pp. 147-149]{anderson_security_2008}. An HMAC instead prefaces the data with a shared key, before using a one-way hash function to generate a message authentication code \citep{krawczyk_hmac_1997}, and thus the result is only verifiable by someone with the same private key.
|
|
|
|
The comparison is as such: signatures provide non-repudiation, while HMACs do not - one can know the owner of which private key signed a message, while anyone with the shared key could have produced an HMAC for a message. The second point is that digital signatures are much more computationally complex than HMACs, and thus, given that the control of both ends lies with the same party, HMAC is the message authentication of choice for this project.
|
|
|
|
\subsubsection{Initial Exchange}
|
|
|
|
An initial exchange at the beginning of a flow must take place for the security of this application. However, one must be wary of the implications of reflection attacks, mentioned in section \ref{section:reflection-attacks}. Given is the chosen authentication exchange for this project:
|
|
|
|
\begin{align*}
|
|
A \longrightarrow B &: \{N_1, A, T_0\}_k \\
|
|
B \longrightarrow A &: \{N_1, A, N_2, B, T_1\}_k \\
|
|
A \longrightarrow B &: \{A, B, N_2, T_2\}_k
|
|
\end{align*}
|
|
|
|
The initial message between $A$ and $B$ is comprised of the following: a nonce, $A$'s identity, and the current time. The nonce is a number used once, ensuring that the initiation message is fresh. $A$ includes its identity to prevent reflection attacks - if $B$ is talking to $C$ and yet the message includes $A$'s identity, it can discard the message. The timestamp is used to cheaply discard messages that are not fresh, and to reduce the storage of nonces, as only nonces within the freshness time need be stored. Further, the timestamp places a time limit on this exchange, allowing flows that have failed to be closed if it has not yet succeeded. Finally, the HMAC of the message is included, demonstrating that $A$ possesses either the correct key, or is replaying the message.
|
|
|
|
The second message is a similarly formatted response. The response from $B$ to $A$ includes $A$'s chosen nonce and $A$'s identity. Then, $B$ chooses a nonce and its identity. The current timestamp is again appended, for the same purpose. This demonstrates that $B$ can produce a HMAC for the arbitrary nonce $A$ has selected, knows that it is $B$, and provides a nonce of its own choice for $A$ to demonstrate their ability to sign.
|
|
|
|
$B$ has multiple reasons checks to perform before replying to $A$'s request. If the message is not sufficiently fresh based on its timestamp, $B$ immediately discards it, at very little computational expense. Secondly, the HMAC can be verified, and if it's not correct, the flow discarded. Finally, the identity of $A$ can be verified against the identifier that it has provided in the message. It is chosen that the identifier $A$ provides should be either the IP address through which it contacts $B$, or an FQDN that resolves to that. This allows a factor of the connection to be compared to the identity, confirming that the details of the connection align with the provided identity. This demonstrates the cryptographic principle of \emph{silence is a virtue}.
|
|
|
|
Finally, $A$ responds to $B$ with both their identities, $B$'s chosen nonce and the current time. At this point, $A$ can be confident that $B$'s identity is correct. $A$ performs the same checks as $B$ previously before responding, maintaining a closed flow in the case of a bad response. The timestamp and HMAC are checked, the values from the previous message verified to be equal, and $B$'s identity compared to that expected. Once these are verified, $A$ is confident that it is talking to $B$, so responds to the message with enough information to confirm to $B$ that it knows who its talking to, $B$'s nonce, and the timestamp and key. This concludes the exchange.
|
|
|
|
It is possible to create shorter crpytographic exchanges, but for this project it is not necessary. The flows generated by this project are very long lived, and as such, the constant length of the initial exchange is amortised. Therefore, keeping the exchange clear and simple is most important.
|
|
|
|
\subsubsection{Message Passing}
|
|
|
|
After authentication, each exchange is then a simple case of providing authenticity for each packet sent. This is as follows, in both directions:
|
|
|
|
\begin{align*}
|
|
A \longrightarrow B &: \{P_0, T_0\}_k \\
|
|
B \longrightarrow A &: \{P_1, T_1\}_k
|
|
\end{align*}
|
|
|
|
This simplicity in messages is chosen to provide a good balance of freshness and per-packet efficiency. Further, it is a composable system. As this project supports multiple transport mechanisms, the $P_0$ can be expanded as necessary, to provide integrity, authenticity and freshness to additional data. An example of this is in figure \ref{fig:udp-packet-structure}, where $P$ includes the congestion control of each message, preventing attacks that would require modifying the congestion control header. However, the freshness guarantee provided by the timestamp here is too weak for some attacks, so is discussed in the next section.
|
|
|
|
\subsection{Replay Attacks}
|
|
\label{section:preparation-repeated-packets}
|
|
|
|
Although a timestamp is included with each packet, the time delay between the packet being dispatched by one side and received by the other is significant. As this is the case, there must be significant flexibility in how old a received packet can be - chosen to be 5 seconds. An attacker, as pictured in figure \ref{fig:mitm-middlebox}, could therefore send a number of packets only limited by their own bandwidth, if they can gain a fresh packet at least once every 5 seconds.
|
|
|
|
To avoid this case, additional measures must be taken to avoid proxying repeated packets. The solution I have chosen is \emph{IPsec Anti-Replay Algorithm without Bit Shifting} \citep{tsou_ipsec_2012}, employed in Wireguard \citep{donenfeld_wireguard_2017}. The implementation of this is given in section \ref{section:implementation-repeated-packets}.
|
|
|
|
The sliding window technique requires each packet to have a consistently increasing sequence number. This takes advantage of the composable structure mentioned above - the sequence number can be placed within the packet sent. The sequence number here must be globally unique within the connection, and thus is not equivalent to the independent sequence number of TCP or UDP flows. This is similar to the issue given in congestion control for multipath TCP, where a second sequence number must be added, named the data sequence number. The data sequence number provides a separation between the loss control of indvidual subflows and the data transfer of the flow as a whole \citep[pp. 11]{wischik_design_2011}.
|
|
|
|
\subsubsection{Transparent Security}
|
|
|
|
It was previously mentioned that this solution focuses on providing transparent security for the proxied packets. Further to this, this solution provides transparent security in the other direction. Consider the case of a satellite that employs both a whole network corporate VPN and this solution. The network can be configured in each of two cases: the multipath proxy runs behind the VPN, or the VPN runs behind the multipath proxy. These two examples are given in figure \ref{fig:whole-network-vpn-transparency}.
|
|
|
|
\begin{figure}
|
|
\centering
|
|
\begin{subfigure}[b]{.49\textwidth}
|
|
\includegraphics[width=\textwidth]{VPNConfig1.jpg}
|
|
\caption{A VPN client behind the multipath proxy.}
|
|
\end{subfigure}
|
|
\begin{subfigure}[b]{.49\textwidth}
|
|
\includegraphics[width=\textwidth]{VPNConfig2.jpg}
|
|
\caption{A VPN client in front of the multipath proxy.}
|
|
\end{subfigure}
|
|
\caption{Two network architectures running a whole network VPN and this solution}
|
|
\label{fig:whole-network-vpn-transparency}
|
|
\end{figure}
|
|
|
|
Both of these setups have their merits. If you have little control over the VPN, it might be necessary to use the first case. However, if the VPN is under your control, the second case is likely a better choice. The security efforts, detailed above, become redundant if the same guarantees are provided at a higher layer. If the overlying VPN connection provides the required security measures, there is little point reimplementing them at the proxying layer, which provides a significant increase in per-packet efficiency. For this reason, all of the security features mentioned above will be configurable, such that this gain in efficiency is realisable.
|
|
|
|
Supporting and encouraging this layering of protocols provides a second benefit: if the security in this solution breaks with time, there are two options to repair it. One can either fix the open source application, or compose it with a security solution that has not broken with time, but perhaps provides too many security guarantees and therefore causes reduced performance.
|
|
|
|
% -------------------------- Language Selection ---------------------------- %
|
|
\section{Language Selection}
|
|
\label{section:language-selection}
|
|
|
|
In this section, I evaluate three potential languages (C++, Rust and Go) for the development of this software. To support this evaluation, I have provided a sample program in each language. The sample program is intended to be a minimal example of reading packets from a TUN interface, placing them in a queue from a single thread, and consuming the packets from the queue with multiple threads. These examples are given in figures \ref{fig:cpp-tun-sample} through \ref{fig:go-tun-sample}.
|
|
|
|
\subsubsection{C++}
|
|
|
|
There are two primary advantages to completing this project in C++: speed of execution, and C++ being low level enough to achieve these goals. The negatives of using C++ are demonstrated in the sample script, given in figure \ref{fig:cpp-tun-sample}. It is immediately obvious that to achieve even the base of this project, the code in C++ is multiple times the length of equivalent code in either Rust or Go.
|
|
|
|
The low level nature of C++ can lead to a lack of portability.
|
|
|
|
\begin{figure}
|
|
\inputminted{cpp}{Preparation/Samples/main.cpp}
|
|
\caption{A sample script written in C++ to collect packets from a TUN interface and print them from multiple threads}
|
|
\label{fig:cpp-tun-sample}
|
|
\end{figure}
|
|
|
|
\subsubsection{Rust}
|
|
|
|
Rust provides advantages over C++ while still maintaining the speed. It is also memory safe, significantly reducing the programming load of searching for memory errors. The Rust sample is given in figure \ref{fig:rust-tun-sample}, and it is pleasantly concise.
|
|
|
|
For the purposes of this project, the downsides of Rust come from its youthfulness. This is two-faceted: IDE support and Crate stability. Firstly, the IDE support for Rust in my IDEs of choice is provided via a plugin to IntelliJ, and is not as well supported as other languages. Secondly, the crate available for TUN support (tun-tap\footnote{\url{https://docs.rs/tun-tap/}}) does not yet provide a stable API, which was noticed during the development of even this test program. Between writing the program initially and re-testing it to place in this document, the API of the Crate had changed to the point where my script no longer type checked. Further, the old version had disappeared, and thus I was left with a program that didn't compile or function. Although writing the API for TUN interaction is not an issue, it would reduce portability.
|
|
|
|
\begin{figure}
|
|
\inputminted{rust}{Preparation/Samples/main.rs}
|
|
\caption{A sample script written in Rust to collect packets from a TUN interface and print them from multiple threads}
|
|
\label{fig:rust-tun-sample}
|
|
\end{figure}
|
|
|
|
\subsubsection{Go}
|
|
|
|
The final language to evaluate is Go, often written as GoLang. It is the language of choice for this project, with the sample provided in figure \ref{fig:go-tun-sample}. Go is significantly higher level than the other two languages mentioned, and provides a memory management model that is both simpler than C++ and more standardised than Rust.
|
|
|
|
For the greedy structure of this project, Go's focus on concurrency is extremely beneficial. Go has channels in the standard runtime, which support any number of both producers and consumers. In this project, both SPMC and MPSC are required, so having these provided as a first class feature of the language is beneficial.
|
|
|
|
Garbage collection and first order concurrency come together to make the code produced for this project highly readable. The downside of this runtime is that the speed of the language is negatively affected. However, I think that for the purposes of this first production, that compromise is acceptable. By producing code that makes the functionality of the application clear, future implementations could more easily be built to mirror it. As the Go implementation can achieve respectable performance, as shown in section \ref{section:performance-evaluation}, the compromise of using a well-suited high-level language is one worth taking.
|
|
|
|
\begin{figure}
|
|
\inputminted{go}{Preparation/Samples/main.go}
|
|
\caption{A sample script written in Go to collect packets from a TUN interface and print them from multiple threads}
|
|
\label{fig:go-tun-sample}
|
|
\end{figure}
|
|
|
|
% ------------------------- Requirements Analysis -------------------------- %
|
|
\section{Requirements Analysis}
|
|
\label{section:requirements-analysis}
|
|
|
|
The requirements of the project are detailed in the Success Criteria of the Project Proposal (Appendix \ref{appendix:project-proposal}), and are the primary method of evaluation for project success. They are split into three categories: success criteria, extended goals and stretch goals.
|
|
|
|
% ------------------------- Engineering Approach --------------------------- %
|
|
\section{Engineering Approach}
|
|
\label{section:engineering-approach}
|
|
|
|
\subsubsection{Software Development Model}
|
|
|
|
The development of this software used the iterative model, with the initial iteration following a waterfall model. The core deliverable of this project is large, such that much programming was required before systems testing became a possibility. The waterfall model best suited this - building the software in separately tested parts, then putting significant focus on systems testing.
|
|
|
|
As many of the requirements laid out in the project proposal's success criteria are quantitative system performance tests, I developed a system to automate this as part of the initial waterfall. This allowed frequent evaluation of the software against the success criteria.
|
|
|
|
The rest of the iterations were much smaller than the first, with each focusing on improving a specific factor. These iterations were continued until the success criteria were satisfied, meaning that the software had met its intended use.
|
|
|
|
\subsubsection{Development Tools}
|
|
|
|
A large part of the language choice focused on development tools. As discussed in section \ref{section:language-selection}, IDE support was important to me. Given that my preferred IDEs are those supplied by JetBrains\footnote{\url{https://jetbrains.com/}}, generously provided for education and academic research free of charge, I used GoLand for the Go development of this project, and PyCharm for the Python evaluation programs. Using an intelligent IDE, particularly with the statically typed Go, significantly increases my productivity as a programmer, and thus reduces incidental complexity.
|
|
|
|
I used Git version control, with a self-hosted Gitea\footnote{\url{https://gitea.com/}} server as the remote. My repositories have a multitude of on- and off-site backups, at varying frequencies (2xUSB + 2xCloud Storage + NAS + Multiple Computers).
|
|
|
|
Alongside my self-hosted Gitea server, I have a self hosted Drone by Harness\footnote{\url{http://drone.io/}} server for continuous integration. This made it simple to add a Drone file to the repository, allowing for the Go tests to be ran, and using a script with the gofmt\footnote{\url{https://golang.org/cmd/gofmt/}} tool.
|
|
|
|
\mint{shell-session}`bash -c "gofmt -l . | wc -l | cmp -s <(echo 0) || (gofmt -l . && exit 1)"`
|
|
|
|
This script, ran by Drone, rejects any pushes to the Git repository that do not conform to the formatting specified by the gofmt tool. Ensuring that all branches are consistently formatted can significantly reduce merge issues.
|
|
|
|
\subsubsection{Licensing}
|
|
|
|
I have chosen to license this software under the MIT license. The MIT license is simple and permissive.
|
|
|
|
% ---------------------------- Starting Point ------------------------------ %
|
|
\section{Starting Point}
|
|
|
|
I had significant experience with the language Go before the start of this project, though not formally taught. My knowledge of networking is limited to that of a user, and the content of the Part IB Tripos courses \emph{Computer Networking} and \emph{Principles of Communication} (the latter given after the start of this project). The security analysis drew from the Part IA course \emph{Software and Security Engineering} and the Part IB course \emph{Security}. As the software is highly concurrent, the Part IB course \emph{Concurrent and Distributed Systems} and the Part II Unit of Assessment \emph{Multicore Semantics and Programming} were applied.
|
|
|
|
% -------------------------------- Summary --------------------------------- %
|
|
\section{Summary}
|
|
|
|
Security is a large area in this project - perhaps more than the single success criteria suggests. This preparation has led to two clear concepts in security: the system must be adaptable in code, and flexible.
|