forked from extern/smegmesh
Compare commits
No commits in common. "main" and "60-unit-test-crdt-data-store" have entirely different histories.
main
...
60-unit-te
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "smegmesh-web"]
|
||||||
|
path = smegmesh-web
|
||||||
|
url = git@github.com:tim-beatham/smegmesh-web.git
|
674
LICENSE
674
LICENSE
@ -1,674 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
|
||||||
or can get the source code. And you must show them these terms so they
|
|
||||||
know their rights.
|
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
|
||||||
that there is no warranty for this free software. For both users' and
|
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
|
||||||
changed, so that their problems will not be attributed erroneously to
|
|
||||||
authors of previous versions.
|
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the special requirements of the GNU Affero General Public License,
|
|
||||||
section 13, concerning interaction through a network will apply to the
|
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
|
||||||
notice like this when it starts in an interactive mode:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
|
||||||
<https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
|
99
README.md
99
README.md
@ -1,97 +1,2 @@
|
|||||||
# smegmesh
|
# wgmesh
|
||||||
|
WireGuard VPN Mesh Management
|
||||||
## Disclaimer
|
|
||||||
|
|
||||||
Submitted to fill the requirements of Msci (Hons) Computer Science at the School of Computer Science, University of St Andrews.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This repository is licensed under the MIT License. See the [LICENSE](./LICENSE) file for more details.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Distributed WireGuard mesh management. This tool helps to configure WireGuard
|
|
||||||
networks in a mesh topology such that there is no single point of failure.
|
|
||||||
The tool aims to set-up mesh networks with minimal knowledge and
|
|
||||||
configuration of WireGuard.
|
|
||||||
|
|
||||||
The idea being that a node can take up one of two roles in the network, a
|
|
||||||
peer or a client. A peer is publicly accessible and must have IPv6 forwarding
|
|
||||||
enabled. Peer's responsibility is routing traffic on behalf of clients
|
|
||||||
associated with it.
|
|
||||||
|
|
||||||
Whereas, a client hides behind a private endpoint in which all packets are
|
|
||||||
routed through the peer. A client must enable the flat `keepAliveWg` to
|
|
||||||
ensure that its associated peer learns about any NAT mappings that change.
|
|
||||||
|
|
||||||
IPv6 is used in the overlay to make use of the larger address space.
|
|
||||||
A node hashes it's WireGuard public key to create an identifier
|
|
||||||
(the last 64-bits of the IPv6 address) and the mesh-id is hashed into
|
|
||||||
the first 64-bits of the IPv6 address to create the locator.
|
|
||||||
|
|
||||||
A node (both client and a peer) can be in multiple meshes at the same
|
|
||||||
time. In which case the node can optionally choose to act as a bridge
|
|
||||||
and forward packets between the two meshes. Through this it is possible
|
|
||||||
to define complex topologies. To route between meshes multiple hops away
|
|
||||||
a simple link-state protocol is adopted (similar to RIP) in which the
|
|
||||||
path length (number of meshes) is used to determine the shortest path.
|
|
||||||
|
|
||||||
Redundant routing is possible to create multiple exit points to the same
|
|
||||||
mesh network. In which case consistent hashing is performed to split traffic
|
|
||||||
between the exit points.
|
|
||||||
|
|
||||||
## Message Dissemination
|
|
||||||
|
|
||||||
A variant of the gossip protocol is used for message dissemination. Each peer
|
|
||||||
in the network is ordered lexicographically ordered by their public key.
|
|
||||||
The node with the lexicographically lowest public key is used as the leader
|
|
||||||
of the mesh. Every `heartBeatInterval` disseminates a refresh message
|
|
||||||
throughout the entirety of the group in order to prune nodes that may
|
|
||||||
have prematurely died.
|
|
||||||
|
|
||||||
If after `3 * heartBeatInterval` a node has not received a dissemination
|
|
||||||
message then the node prunes the leader and expects one from the next
|
|
||||||
lexicographically lowest public key.
|
|
||||||
|
|
||||||
To 'merge' updates and reconcile any conflicts a Conflict Free Replicated
|
|
||||||
Data Type (CRDT) is implemented. Consisting of an add and remove set.
|
|
||||||
Where a node is in the group if it is in the add set and there is either
|
|
||||||
no entry in the remove set or the timestamp in the remove set has a lower
|
|
||||||
vector clock value.
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
This prototype has been tested to a scale of 3000 peers in the network.
|
|
||||||
Furthermore, the fault-tolerance has been tested to a scale 3000 nodes
|
|
||||||
to the order of 20 seconds for the entire network and 12 seconds
|
|
||||||
for the 99 percentile.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
To build the project do: `go build -v ./...`. A Docker file is provided
|
|
||||||
to get started.
|
|
||||||
|
|
||||||
To build with the Dockerfile:
|
|
||||||
`docker build -t smegmesh-base ./`
|
|
||||||
|
|
||||||
Then run an example topology in the examples folder. For example:
|
|
||||||
`cd examples/simple && docker-compose up -d`
|
|
||||||
|
|
||||||
## Tools
|
|
||||||
|
|
||||||
### Smegd
|
|
||||||
Smegmesh requires the daemon process to be running (smegd) which also takes
|
|
||||||
a configuration.yaml file. An example yaml configuration file is provided in
|
|
||||||
examples/simple/shared/configuration.
|
|
||||||
|
|
||||||
### Smegctl
|
|
||||||
Smegctl is a CLI tool to create, join, visualise and administer networks.
|
|
||||||
|
|
||||||
### Api
|
|
||||||
An api is provided to invoke functions to create, join, visualise and administer
|
|
||||||
networks. This could be used to create an application that allows a user
|
|
||||||
to configure the networks.
|
|
||||||
|
|
||||||
### Dns
|
|
||||||
A dns server is provided to resolve an alias into an IPv6 address.
|
|
||||||
|
|
@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/api"
|
"github.com/tim-beatham/wgmesh/pkg/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
smegdns "github.com/tim-beatham/smegmesh/pkg/dns"
|
smegdns "github.com/tim-beatham/wgmesh/pkg/dns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -6,10 +6,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/akamensky/argparse"
|
"github.com/akamensky/argparse"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
graph "github.com/tim-beatham/smegmesh/pkg/dot"
|
graph "github.com/tim-beatham/wgmesh/pkg/dot"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ipc"
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
||||||
@ -22,22 +22,25 @@ type CreateMeshParams struct {
|
|||||||
AdvertiseDefault bool
|
AdvertiseDefault bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMesh(client *ipc.SmegmeshIpc, args *ipc.NewMeshArgs) {
|
func createMesh(params *CreateMeshParams) string {
|
||||||
var reply string
|
var reply string
|
||||||
err := client.CreateMesh(args, &reply)
|
newMeshParams := ipc.NewMeshArgs{
|
||||||
|
WgArgs: params.WgArgs,
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(reply)
|
err := params.Client.Call("IpcHandler.CreateMesh", &newMeshParams, &reply)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply
|
||||||
}
|
}
|
||||||
|
|
||||||
func listMeshes(client *ipc.SmegmeshIpc) {
|
func listMeshes(client *ipcRpc.Client) {
|
||||||
reply := new(ipc.ListMeshReply)
|
reply := new(ipc.ListMeshReply)
|
||||||
|
|
||||||
err := client.ListMeshes(reply)
|
err := client.Call("IpcHandler.ListMeshes", "", &reply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log.WriteErrorf(err.Error())
|
logging.Log.WriteErrorf(err.Error())
|
||||||
@ -49,38 +52,54 @@ func listMeshes(client *ipc.SmegmeshIpc) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func joinMesh(client *ipc.SmegmeshIpc, args ipc.JoinMeshArgs) {
|
type JoinMeshParams struct {
|
||||||
var reply string
|
Client *ipcRpc.Client
|
||||||
|
MeshId string
|
||||||
err := client.JoinMesh(args, &reply)
|
IpAddress string
|
||||||
|
Endpoint string
|
||||||
if err != nil {
|
WgArgs ipc.WireGuardArgs
|
||||||
fmt.Print(err.Error())
|
AdvertiseRoutes bool
|
||||||
}
|
AdvertiseDefault bool
|
||||||
|
|
||||||
fmt.Println(reply)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func leaveMesh(client *ipc.SmegmeshIpc, meshId string) {
|
func joinMesh(params *JoinMeshParams) string {
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
err := client.LeaveMesh(meshId, &reply)
|
args := ipc.JoinMeshArgs{
|
||||||
|
MeshId: params.MeshId,
|
||||||
|
IpAdress: params.IpAddress,
|
||||||
|
WgArgs: params.WgArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := params.Client.Call("IpcHandler.JoinMesh", &args, &reply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Print(err.Error())
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply
|
||||||
|
}
|
||||||
|
|
||||||
|
func leaveMesh(client *ipcRpc.Client, meshId string) {
|
||||||
|
var reply string
|
||||||
|
|
||||||
|
err := client.Call("IpcHandler.LeaveMesh", &meshId, &reply)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(reply)
|
fmt.Println(reply)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getGraph(client *ipc.SmegmeshIpc) {
|
func getGraph(client *ipcRpc.Client) {
|
||||||
listMeshesReply := new(ipc.ListMeshReply)
|
listMeshesReply := new(ipc.ListMeshReply)
|
||||||
|
|
||||||
err := client.ListMeshes(listMeshesReply)
|
err := client.Call("IpcHandler.ListMeshes", "", &listMeshesReply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Print(err.Error())
|
fmt.Println(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +108,7 @@ func getGraph(client *ipc.SmegmeshIpc) {
|
|||||||
for _, meshId := range listMeshesReply.Meshes {
|
for _, meshId := range listMeshesReply.Meshes {
|
||||||
var meshReply ipc.GetMeshReply
|
var meshReply ipc.GetMeshReply
|
||||||
|
|
||||||
err := client.GetMesh(meshId, &meshReply)
|
err := client.Call("IpcHandler.GetMesh", &meshId, &meshReply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
@ -110,15 +129,10 @@ func getGraph(client *ipc.SmegmeshIpc) {
|
|||||||
fmt.Println(dot)
|
fmt.Println(dot)
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryMesh(client *ipc.SmegmeshIpc, meshId, query string) {
|
func queryMesh(client *ipcRpc.Client, meshId, query string) {
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
args := ipc.QueryMesh{
|
err := client.Call("IpcHandler.Query", &ipc.QueryMesh{MeshId: meshId, Query: query}, &reply)
|
||||||
MeshId: meshId,
|
|
||||||
Query: query,
|
|
||||||
}
|
|
||||||
|
|
||||||
err := client.Query(args, &reply)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
@ -128,13 +142,11 @@ func queryMesh(client *ipc.SmegmeshIpc, meshId, query string) {
|
|||||||
fmt.Println(reply)
|
fmt.Println(reply)
|
||||||
}
|
}
|
||||||
|
|
||||||
func putDescription(client *ipc.SmegmeshIpc, meshId, description string) {
|
// putDescription: puts updates the description about the node to the meshes
|
||||||
|
func putDescription(client *ipcRpc.Client, description string) {
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
err := client.PutDescription(ipc.PutDescriptionArgs{
|
err := client.Call("IpcHandler.PutDescription", &description, &reply)
|
||||||
MeshId: meshId,
|
|
||||||
Description: description,
|
|
||||||
}, &reply)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
@ -145,46 +157,41 @@ func putDescription(client *ipc.SmegmeshIpc, meshId, description string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// putAlias: puts an alias for the node
|
// putAlias: puts an alias for the node
|
||||||
func putAlias(client *ipc.SmegmeshIpc, meshid, alias string) {
|
func putAlias(client *ipcRpc.Client, alias string) {
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
err := client.PutAlias(ipc.PutAliasArgs{
|
err := client.Call("IpcHandler.PutAlias", &alias, &reply)
|
||||||
MeshId: meshid,
|
|
||||||
Alias: alias,
|
|
||||||
}, &reply)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Print(err.Error())
|
fmt.Println(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(reply)
|
fmt.Println(reply)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setService(client *ipc.SmegmeshIpc, meshId, service, value string) {
|
func setService(client *ipcRpc.Client, service, value string) {
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
err := client.PutService(ipc.PutServiceArgs{
|
serviceArgs := &ipc.PutServiceArgs{
|
||||||
MeshId: meshId,
|
|
||||||
Service: service,
|
Service: service,
|
||||||
Value: value,
|
Value: value,
|
||||||
}, &reply)
|
}
|
||||||
|
|
||||||
|
err := client.Call("IpcHandler.PutService", serviceArgs, &reply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Print(err.Error())
|
fmt.Println(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(reply)
|
fmt.Println(reply)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteService(client *ipc.SmegmeshIpc, meshId, service string) {
|
func deleteService(client *ipcRpc.Client, service string) {
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
err := client.DeleteService(ipc.DeleteServiceArgs{
|
err := client.Call("IpcHandler.PutService", &service, &reply)
|
||||||
MeshId: meshId,
|
|
||||||
Service: service,
|
|
||||||
}, &reply)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
@ -195,8 +202,8 @@ func deleteService(client *ipc.SmegmeshIpc, meshId, service string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
parser := argparse.NewParser("smgctl",
|
parser := argparse.NewParser("wg-mesh",
|
||||||
"smegctl Manipulate WireGuard mesh networks")
|
"wg-mesh Manipulate WireGuard mesh networks")
|
||||||
|
|
||||||
newMeshCmd := parser.NewCommand("new-mesh", "Create a new mesh")
|
newMeshCmd := parser.NewCommand("new-mesh", "Create a new mesh")
|
||||||
listMeshCmd := parser.NewCommand("list-meshes", "List meshes the node is connected to")
|
listMeshCmd := parser.NewCommand("list-meshes", "List meshes the node is connected to")
|
||||||
@ -219,11 +226,14 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
var newMeshRole *string = newMeshCmd.Selector("r", "role", []string{"peer", "client"}, &argparse.Options{
|
var newMeshRole *string = newMeshCmd.Selector("r", "role", []string{"peer", "client"}, &argparse.Options{
|
||||||
Help: "Role in the mesh network. A peer is publicly route-able, whereas a client sits behind a private endpoint",
|
Default: "peer",
|
||||||
|
Help: "Role in the mesh network. A value of peer means that the node is publicly routeable and thus considered" +
|
||||||
|
" in the gossip protocol. Client means that the node is not publicly routeable and is not a candidate in the gossip" +
|
||||||
|
" protocol",
|
||||||
})
|
})
|
||||||
var newMeshKeepAliveWg *int = newMeshCmd.Int("k", "KeepAliveWg", &argparse.Options{
|
var newMeshKeepAliveWg *int = newMeshCmd.Int("k", "KeepAliveWg", &argparse.Options{
|
||||||
Default: 0,
|
Default: 0,
|
||||||
Help: "WireGuard KeepAlive value for NAT traversal and firewall hole-punching",
|
Help: "WireGuard KeepAlive value for NAT traversal and firewall holepunching",
|
||||||
})
|
})
|
||||||
|
|
||||||
var newMeshAdvertiseRoutes *bool = newMeshCmd.Flag("a", "advertise", &argparse.Options{
|
var newMeshAdvertiseRoutes *bool = newMeshCmd.Flag("a", "advertise", &argparse.Options{
|
||||||
@ -249,9 +259,10 @@ func main() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
var joinMeshRole *string = joinMeshCmd.Selector("r", "role", []string{"peer", "client"}, &argparse.Options{
|
var joinMeshRole *string = joinMeshCmd.Selector("r", "role", []string{"peer", "client"}, &argparse.Options{
|
||||||
Help: "Role in the mesh network. A value of peer means that the node is publicly route-able acting as a router " +
|
Default: "peer",
|
||||||
"for clients to route packets through. A client sits behind a private endpoint and routes traffic through a single " +
|
Help: "Role in the mesh network. A value of peer means that the node is publicly routeable and thus considered" +
|
||||||
"endpoint",
|
" in the gossip protocol. Client means that the node is not publicly routeable and is not a candidate in the gossip" +
|
||||||
|
" protocol",
|
||||||
})
|
})
|
||||||
|
|
||||||
var joinMeshPort *int = joinMeshCmd.Int("p", "wgport", &argparse.Options{
|
var joinMeshPort *int = joinMeshCmd.Int("p", "wgport", &argparse.Options{
|
||||||
@ -291,16 +302,6 @@ func main() {
|
|||||||
Help: "Description of the node in the mesh",
|
Help: "Description of the node in the mesh",
|
||||||
})
|
})
|
||||||
|
|
||||||
var descriptionMeshId *string = putDescriptionCmd.String("m", "meshid", &argparse.Options{
|
|
||||||
Required: true,
|
|
||||||
Help: "MeshID of the mesh network to join",
|
|
||||||
})
|
|
||||||
|
|
||||||
var aliasMeshId *string = putAliasCmd.String("m", "meshid", &argparse.Options{
|
|
||||||
Required: true,
|
|
||||||
Help: "MeshID of the mesh network to join",
|
|
||||||
})
|
|
||||||
|
|
||||||
var alias *string = putAliasCmd.String("a", "alias", &argparse.Options{
|
var alias *string = putAliasCmd.String("a", "alias", &argparse.Options{
|
||||||
Required: true,
|
Required: true,
|
||||||
Help: "Alias of the node to set can be used in DNS to lookup an IP address",
|
Help: "Alias of the node to set can be used in DNS to lookup an IP address",
|
||||||
@ -315,21 +316,11 @@ func main() {
|
|||||||
Help: "Value of the service to advertise in the mesh network",
|
Help: "Value of the service to advertise in the mesh network",
|
||||||
})
|
})
|
||||||
|
|
||||||
var serviceMeshId *string = setServiceCmd.String("m", "meshid", &argparse.Options{
|
|
||||||
Required: true,
|
|
||||||
Help: "MeshID of the mesh network to join",
|
|
||||||
})
|
|
||||||
|
|
||||||
var deleteServiceKey *string = deleteServiceCmd.String("s", "service", &argparse.Options{
|
var deleteServiceKey *string = deleteServiceCmd.String("s", "service", &argparse.Options{
|
||||||
Required: true,
|
Required: true,
|
||||||
Help: "Key of the service to remove",
|
Help: "Key of the service to remove",
|
||||||
})
|
})
|
||||||
|
|
||||||
var deleteServiceMeshid *string = deleteServiceCmd.String("m", "meshid", &argparse.Options{
|
|
||||||
Required: true,
|
|
||||||
Help: "MeshID of the mesh network to join",
|
|
||||||
})
|
|
||||||
|
|
||||||
err := parser.Parse(os.Args)
|
err := parser.Parse(os.Args)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -337,13 +328,16 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := ipc.NewClientIpc()
|
client, err := ipcRpc.DialHTTP("unix", SockAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
fmt.Println(err.Error())
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if newMeshCmd.Happened() {
|
if newMeshCmd.Happened() {
|
||||||
args := &ipc.NewMeshArgs{
|
fmt.Println(createMesh(&CreateMeshParams{
|
||||||
|
Client: client,
|
||||||
|
Endpoint: *newMeshEndpoint,
|
||||||
WgArgs: ipc.WireGuardArgs{
|
WgArgs: ipc.WireGuardArgs{
|
||||||
Endpoint: *newMeshEndpoint,
|
Endpoint: *newMeshEndpoint,
|
||||||
Role: *newMeshRole,
|
Role: *newMeshRole,
|
||||||
@ -352,9 +346,7 @@ func main() {
|
|||||||
AdvertiseDefaultRoute: *newMeshAdvertiseDefaults,
|
AdvertiseDefaultRoute: *newMeshAdvertiseDefaults,
|
||||||
AdvertiseRoutes: *newMeshAdvertiseRoutes,
|
AdvertiseRoutes: *newMeshAdvertiseRoutes,
|
||||||
},
|
},
|
||||||
}
|
}))
|
||||||
|
|
||||||
createMesh(client, args)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if listMeshCmd.Happened() {
|
if listMeshCmd.Happened() {
|
||||||
@ -362,9 +354,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if joinMeshCmd.Happened() {
|
if joinMeshCmd.Happened() {
|
||||||
args := ipc.JoinMeshArgs{
|
fmt.Println(joinMesh(&JoinMeshParams{
|
||||||
|
Client: client,
|
||||||
IpAddress: *joinMeshIpAddress,
|
IpAddress: *joinMeshIpAddress,
|
||||||
MeshId: *joinMeshId,
|
MeshId: *joinMeshId,
|
||||||
|
Endpoint: *joinMeshEndpoint,
|
||||||
WgArgs: ipc.WireGuardArgs{
|
WgArgs: ipc.WireGuardArgs{
|
||||||
Endpoint: *joinMeshEndpoint,
|
Endpoint: *joinMeshEndpoint,
|
||||||
Role: *joinMeshRole,
|
Role: *joinMeshRole,
|
||||||
@ -373,8 +367,7 @@ func main() {
|
|||||||
AdvertiseDefaultRoute: *joinMeshAdvertiseDefaults,
|
AdvertiseDefaultRoute: *joinMeshAdvertiseDefaults,
|
||||||
AdvertiseRoutes: *joinMeshAdvertiseRoutes,
|
AdvertiseRoutes: *joinMeshAdvertiseRoutes,
|
||||||
},
|
},
|
||||||
}
|
}))
|
||||||
joinMesh(client, args)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if getGraphCmd.Happened() {
|
if getGraphCmd.Happened() {
|
||||||
@ -390,18 +383,18 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if putDescriptionCmd.Happened() {
|
if putDescriptionCmd.Happened() {
|
||||||
putDescription(client, *descriptionMeshId, *description)
|
putDescription(client, *description)
|
||||||
}
|
}
|
||||||
|
|
||||||
if putAliasCmd.Happened() {
|
if putAliasCmd.Happened() {
|
||||||
putAlias(client, *aliasMeshId, *alias)
|
putAlias(client, *alias)
|
||||||
}
|
}
|
||||||
|
|
||||||
if setServiceCmd.Happened() {
|
if setServiceCmd.Happened() {
|
||||||
setService(client, *serviceMeshId, *serviceKey, *serviceValue)
|
setService(client, *serviceKey, *serviceValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
if deleteServiceCmd.Happened() {
|
if deleteServiceCmd.Happened() {
|
||||||
deleteService(client, *deleteServiceMeshid, *deleteServiceKey)
|
deleteService(client, *deleteServiceKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,5 +10,5 @@ syncRate: 1
|
|||||||
interClusterChance: 0.15
|
interClusterChance: 0.15
|
||||||
branchRate: 3
|
branchRate: 3
|
||||||
infectionCount: 3
|
infectionCount: 3
|
||||||
heartBeatTime: 10
|
keepAliveTime: 10
|
||||||
pruneTime: 20
|
pruneTime: 20
|
||||||
|
@ -1,34 +1,34 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"net/http"
|
||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
robin "github.com/tim-beatham/smegmesh/pkg/cplane"
|
ctrlserver "github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
ctrlserver "github.com/tim-beatham/smegmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ipc"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/sync"
|
"github.com/tim-beatham/wgmesh/pkg/robin"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/sync"
|
||||||
|
timer "github.com/tim-beatham/wgmesh/pkg/timers"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
if len(os.Args) != 2 {
|
if len(os.Args) != 2 {
|
||||||
logging.Log.WriteErrorf("Did not provide configuration")
|
logging.Log.WriteErrorf("Did not provide configuration")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration, err := conf.ParseDaemonConfiguration(os.Args[1])
|
conf, err := conf.ParseDaemonConfiguration(os.Args[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log.WriteErrorf("Could not parse configuration: %s", err.Error())
|
logging.Log.WriteErrorf("Could not parse configuration: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.SetLogger(logging.NewLogrusLogger(configuration.LogLevel))
|
|
||||||
|
|
||||||
client, err := wgctrl.New()
|
client, err := wgctrl.New()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -36,24 +36,34 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.Profile {
|
||||||
|
go func() {
|
||||||
|
http.ListenAndServe("localhost:6060", nil)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
var robinRpc robin.WgRpc
|
var robinRpc robin.WgRpc
|
||||||
var robinIpc robin.IpcHandler
|
var robinIpc robin.IpcHandler
|
||||||
var syncProvider sync.SyncServiceImpl
|
var syncProvider sync.SyncServiceImpl
|
||||||
|
var syncRequester sync.SyncRequester
|
||||||
|
var syncer sync.Syncer
|
||||||
|
|
||||||
ctrlServerParams := ctrlserver.NewCtrlServerParams{
|
ctrlServerParams := ctrlserver.NewCtrlServerParams{
|
||||||
Conf: configuration,
|
Conf: conf,
|
||||||
CtrlProvider: &robinRpc,
|
CtrlProvider: &robinRpc,
|
||||||
SyncProvider: &syncProvider,
|
SyncProvider: &syncProvider,
|
||||||
Client: client,
|
Client: client,
|
||||||
|
OnDelete: func(mp mesh.MeshProvider) {
|
||||||
|
syncer.SyncMeshes()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrlServer, err := ctrlserver.NewCtrlServer(&ctrlServerParams)
|
ctrlServer, err := ctrlserver.NewCtrlServer(&ctrlServerParams)
|
||||||
|
syncProvider.Server = ctrlServer
|
||||||
if err != nil {
|
syncRequester = sync.NewSyncRequester(ctrlServer)
|
||||||
panic(err)
|
syncer = sync.NewSyncer(ctrlServer.MeshManager, conf, syncRequester)
|
||||||
}
|
syncScheduler := sync.NewSyncScheduler(ctrlServer, syncRequester, syncer)
|
||||||
|
keepAlive := timer.NewTimestampScheduler(ctrlServer)
|
||||||
syncProvider.MeshManager = ctrlServer.MeshManager
|
|
||||||
|
|
||||||
robinIpcParams := robin.RobinIpcParams{
|
robinIpcParams := robin.RobinIpcParams{
|
||||||
CtrlServer: ctrlServer,
|
CtrlServer: ctrlServer,
|
||||||
@ -67,11 +77,16 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.Log.WriteInfof("running ipc handler")
|
logging.Log.WriteInfof("Running IPC Handler")
|
||||||
|
|
||||||
go ipc.RunIpcHandler(&robinIpc)
|
go ipc.RunIpcHandler(&robinIpc)
|
||||||
|
go syncScheduler.Run()
|
||||||
|
go keepAlive.Run()
|
||||||
|
|
||||||
closeResources := func() {
|
closeResources := func() {
|
||||||
logging.Log.WriteInfof("closing resources")
|
logging.Log.WriteInfof("Closing resources")
|
||||||
|
syncScheduler.Stop()
|
||||||
|
keepAlive.Stop()
|
||||||
ctrlServer.Close()
|
ctrlServer.Close()
|
||||||
client.Close()
|
client.Close()
|
||||||
}
|
}
|
@ -1,32 +0,0 @@
|
|||||||
# Paths to the certificates modify
|
|
||||||
# if not running from Smegmesh
|
|
||||||
certificatePath: "./cert/cert.pem"
|
|
||||||
privateKeyPath: "./cert/priv.pem"
|
|
||||||
caCertificatePath: "./cert/cacert.pem"
|
|
||||||
skipCertVerification: true
|
|
||||||
# timeout is the configured grpc timeout
|
|
||||||
timeout: 5
|
|
||||||
# gRPC port to run the solution
|
|
||||||
gRPCPort: 4000
|
|
||||||
# stubWg: whether to install WireGuard configurations
|
|
||||||
# if true just tests the control plane
|
|
||||||
stubWg: false
|
|
||||||
heartbeatInterval: 60
|
|
||||||
branch: 3
|
|
||||||
pullInterval: 20
|
|
||||||
infectionCount: 3
|
|
||||||
interClusterChance: 0.15
|
|
||||||
syncInterval: 10
|
|
||||||
clusterSize: 64
|
|
||||||
logLevel: "info"
|
|
||||||
baseConfiguration:
|
|
||||||
# ipDiscovery: specifies how to find your IP address
|
|
||||||
ipDiscovery: "outgoing"
|
|
||||||
# alternative to ipDiscovery specify an actual endpoint yourself with publicEndpoint: "xxxx"
|
|
||||||
# role is the role that you are playing (peer | client)
|
|
||||||
# peers can only bootstrap meshes
|
|
||||||
role: "client"
|
|
||||||
# advertise meshes to other meshes
|
|
||||||
advertiseRoute: true
|
|
||||||
# advertise default routes
|
|
||||||
advertiseDefaults: true
|
|
@ -1,33 +0,0 @@
|
|||||||
# Paths to the certificates modify
|
|
||||||
# if not running from Smegmesh
|
|
||||||
certificatePath: "./cert/cert.pem"
|
|
||||||
privateKeyPath: "./cert/priv.pem"
|
|
||||||
caCertificatePath: "./cert/cacert.pem"
|
|
||||||
skipCertVerification: true
|
|
||||||
# timeout is the configured grpc timeout
|
|
||||||
timeout: 5
|
|
||||||
# gRPC port to run the solution
|
|
||||||
gRPCPort: 4000
|
|
||||||
# stubWg: whether to install WireGuard configurations
|
|
||||||
# if true just tests the control plane
|
|
||||||
stubWg: false
|
|
||||||
heartbeatInterval: 60
|
|
||||||
branch: 3
|
|
||||||
pullInterval: 20
|
|
||||||
infectionCount: 3
|
|
||||||
interClusterChance: 0.15
|
|
||||||
syncInterval: 2
|
|
||||||
clusterSize: 64
|
|
||||||
logLevel: "info"
|
|
||||||
baseConfiguration:
|
|
||||||
# ipDiscovery: specifies how to find your IP address
|
|
||||||
ipDiscovery: "outgoing"
|
|
||||||
# alternative to ipDiscovery specify an actual endpoint yourself with publicEndpoint: "xxxx"
|
|
||||||
# role is the role that you are playing (peer | client)
|
|
||||||
# peers can only bootstrap meshes
|
|
||||||
role: "peer"
|
|
||||||
# advertise meshes to other meshes
|
|
||||||
advertiseRoute: true
|
|
||||||
# advertise default routes
|
|
||||||
advertiseDefaults: true
|
|
||||||
|
|
95
examples/meshtomesh/docker-compose.yaml
Normal file
95
examples/meshtomesh/docker-compose.yaml
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
version: '3'
|
||||||
|
networks:
|
||||||
|
net-1:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
driver: default
|
||||||
|
config:
|
||||||
|
- subnet: 10.89.0.0/17
|
||||||
|
net-2:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
driver: default
|
||||||
|
config:
|
||||||
|
- subnet: 10.89.155.0/17
|
||||||
|
services:
|
||||||
|
wg-1:
|
||||||
|
image: wg-mesh-base:latest
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_RAW
|
||||||
|
tty: true
|
||||||
|
networks:
|
||||||
|
- net-1
|
||||||
|
volumes:
|
||||||
|
- ./shared:/shared
|
||||||
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
|
wg-2:
|
||||||
|
image: wg-mesh-base:latest
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_RAW
|
||||||
|
tty: true
|
||||||
|
networks:
|
||||||
|
- net-1
|
||||||
|
volumes:
|
||||||
|
- ./shared:/shared
|
||||||
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
|
wg-3:
|
||||||
|
image: wg-mesh-base:latest
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_RAW
|
||||||
|
tty: true
|
||||||
|
networks:
|
||||||
|
- net-1
|
||||||
|
volumes:
|
||||||
|
- ./shared:/shared
|
||||||
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
|
wg-4:
|
||||||
|
image: wg-mesh-base:latest
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_RAW
|
||||||
|
tty: true
|
||||||
|
sysctls:
|
||||||
|
- net.ipv6.conf.all.forwarding=1
|
||||||
|
networks:
|
||||||
|
- net-1
|
||||||
|
- net-2
|
||||||
|
volumes:
|
||||||
|
- ./shared:/shared
|
||||||
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
|
wg-5:
|
||||||
|
image: wg-mesh-base:latest
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_RAW
|
||||||
|
tty: true
|
||||||
|
networks:
|
||||||
|
- net-2
|
||||||
|
volumes:
|
||||||
|
- ./shared:/shared
|
||||||
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
|
wg-6:
|
||||||
|
image: wg-mesh-base:latest
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_RAW
|
||||||
|
tty: true
|
||||||
|
networks:
|
||||||
|
- net-2
|
||||||
|
volumes:
|
||||||
|
- ./shared:/shared
|
||||||
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
|
wg-7:
|
||||||
|
image: wg-mesh-base:latest
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
- NET_RAW
|
||||||
|
tty: true
|
||||||
|
networks:
|
||||||
|
- net-2
|
||||||
|
volumes:
|
||||||
|
- ./shared:/shared
|
||||||
|
command: "wgmeshd /shared/configuration.yaml"
|
14
examples/meshtomesh/shared/configuration.yaml
Normal file
14
examples/meshtomesh/shared/configuration.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
certificatePath: "/wgmesh/cert/cert.pem"
|
||||||
|
privateKeyPath: "/wgmesh/cert/priv.pem"
|
||||||
|
caCertificatePath: "/wgmesh/cert/cacert.pem"
|
||||||
|
skipCertVerification: true
|
||||||
|
timeout: 5
|
||||||
|
gRPCPort: "21906"
|
||||||
|
advertiseRoutes: true
|
||||||
|
clusterSize: 32
|
||||||
|
syncRate: 1
|
||||||
|
interClusterChance: 0.15
|
||||||
|
branchRate: 3
|
||||||
|
infectionCount: 3
|
||||||
|
keepAliveTime: 10
|
||||||
|
pruneTime: 20
|
@ -1,14 +1,14 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
networks:
|
networks:
|
||||||
net-1:
|
net-1:
|
||||||
enable_ipv6: true
|
driver: bridge
|
||||||
ipam:
|
ipam:
|
||||||
driver: default
|
driver: default
|
||||||
config:
|
config:
|
||||||
- subnet: 2001:db8::/64
|
- subnet: 10.89.0.0/17
|
||||||
services:
|
services:
|
||||||
wg-1:
|
wg-1:
|
||||||
image: smegmesh-base:latest
|
image: wg-mesh-base:latest
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
- NET_RAW
|
- NET_RAW
|
||||||
@ -17,12 +17,9 @@ services:
|
|||||||
- net-1
|
- net-1
|
||||||
volumes:
|
volumes:
|
||||||
- ./shared:/shared
|
- ./shared:/shared
|
||||||
command: "smegd /shared/configuration.yaml"
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
sysctls:
|
|
||||||
- net.ipv6.conf.all.forwarding=1
|
|
||||||
- net.ipv6.conf.all.disable_ipv6=0
|
|
||||||
wg-2:
|
wg-2:
|
||||||
image: smegmesh-base:latest
|
image: wg-mesh-base:latest
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
- NET_RAW
|
- NET_RAW
|
||||||
@ -31,12 +28,9 @@ services:
|
|||||||
- net-1
|
- net-1
|
||||||
volumes:
|
volumes:
|
||||||
- ./shared:/shared
|
- ./shared:/shared
|
||||||
command: "smegd /shared/configuration.yaml"
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
sysctls:
|
|
||||||
- net.ipv6.conf.all.forwarding=1
|
|
||||||
- net.ipv6.conf.all.disable_ipv6=0
|
|
||||||
wg-3:
|
wg-3:
|
||||||
image: smegmesh-base:latest
|
image: wg-mesh-base:latest
|
||||||
cap_add:
|
cap_add:
|
||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
- NET_RAW
|
- NET_RAW
|
||||||
@ -45,7 +39,4 @@ services:
|
|||||||
- net-1
|
- net-1
|
||||||
volumes:
|
volumes:
|
||||||
- ./shared:/shared
|
- ./shared:/shared
|
||||||
command: "smegd /shared/configuration.yaml"
|
command: "wgmeshd /shared/configuration.yaml"
|
||||||
sysctls:
|
|
||||||
- net.ipv6.conf.all.forwarding=1
|
|
||||||
- net.ipv6.conf.all.disable_ipv6=0
|
|
||||||
|
@ -1,32 +1,14 @@
|
|||||||
# Paths to the certificates modify
|
certificatePath: "/wgmesh/cert/cert.pem"
|
||||||
# if not running from Smegmesh
|
privateKeyPath: "/wgmesh/cert/priv.pem"
|
||||||
certificatePath: "./cert/cert.pem"
|
caCertificatePath: "/wgmesh/cert/cacert.pem"
|
||||||
privateKeyPath: "./cert/priv.pem"
|
|
||||||
caCertificatePath: "./cert/cacert.pem"
|
|
||||||
skipCertVerification: true
|
skipCertVerification: true
|
||||||
# timeout is the configured grpc timeout
|
|
||||||
timeout: 5
|
timeout: 5
|
||||||
# gRPC port to run the solution
|
gRPCPort: "21906"
|
||||||
gRPCPort: 4000
|
advertiseRoutes: true
|
||||||
# stubWg: whether to install WireGuard configurations
|
clusterSize: 32
|
||||||
# if true just tests the control plane
|
syncRate: 1
|
||||||
stubWg: false
|
|
||||||
heartbeatInterval: 60
|
|
||||||
branch: 3
|
|
||||||
pullInterval: 20
|
|
||||||
infectionCount: 3
|
|
||||||
interClusterChance: 0.15
|
interClusterChance: 0.15
|
||||||
syncInterval: 2
|
branchRate: 3
|
||||||
clusterSize: 64
|
infectionCount: 3
|
||||||
logLevel: "info"
|
keepAliveTime: 10
|
||||||
baseConfiguration:
|
pruneTime: 20
|
||||||
# ipDiscovery: specifies how to find your IP address
|
|
||||||
ipDiscovery: "outgoing"
|
|
||||||
# alternative to ipDiscovery specify an actual endpoint yourself with publicEndpoint: "xxxx"
|
|
||||||
# role is the role that you are playing (peer | client)
|
|
||||||
# peers can only bootstrap meshes
|
|
||||||
role: "peer"
|
|
||||||
# advertise meshes to other meshes
|
|
||||||
advertiseRoute: true
|
|
||||||
# advertise default routes
|
|
||||||
advertiseDefaults: true
|
|
||||||
|
4
go.mod
4
go.mod
@ -1,4 +1,4 @@
|
|||||||
module github.com/tim-beatham/smegmesh
|
module github.com/tim-beatham/wgmesh
|
||||||
|
|
||||||
go 1.21.3
|
go 1.21.3
|
||||||
|
|
||||||
@ -11,11 +11,11 @@ require (
|
|||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/jmespath/go-jmespath v0.4.0
|
github.com/jmespath/go-jmespath v0.4.0
|
||||||
github.com/jsimonetti/rtnetlink v1.3.5
|
github.com/jsimonetti/rtnetlink v1.3.5
|
||||||
github.com/lithammer/shortuuid v3.0.0+incompatible
|
|
||||||
github.com/miekg/dns v1.1.57
|
github.com/miekg/dns v1.1.57
|
||||||
github.com/sirupsen/logrus v1.9.3
|
github.com/sirupsen/logrus v1.9.3
|
||||||
golang.org/x/sys v0.14.0
|
golang.org/x/sys v0.14.0
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6
|
||||||
|
gonum.org/v1/gonum v0.14.0
|
||||||
google.golang.org/grpc v1.58.1
|
google.golang.org/grpc v1.58.1
|
||||||
google.golang.org/protobuf v1.31.0
|
google.golang.org/protobuf v1.31.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
6
go.sum
6
go.sum
@ -27,6 +27,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
|||||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||||
|
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
|
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
|
||||||
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
@ -55,8 +57,6 @@ github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZX
|
|||||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||||
github.com/lithammer/shortuuid v3.0.0+incompatible h1:NcD0xWW/MZYXEHa6ITy6kaXN5nwm/V115vj2YXfhS0w=
|
|
||||||
github.com/lithammer/shortuuid v3.0.0+incompatible/go.mod h1:FR74pbAuElzOUuenUHTK2Tciko1/vKuIKS9dSkDrA4w=
|
|
||||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
github.com/mdlayher/genetlink v1.3.2 h1:KdrNKe+CTu+IbZnm/GVUMXSqBBLqcGpRDa0xkQy56gw=
|
||||||
@ -123,6 +123,8 @@ golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1 h1:EY138uSo1JYlDq+
|
|||||||
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4=
|
golang.zx2c4.com/wireguard v0.0.0-20230704135630-469159ecf7d1/go.mod h1:tqur9LnfstdR9ep2LaJT4lFUl0EjlHtge+gAjmsHUG4=
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6 h1:CawjfCvYQH2OU3/TnxLx97WDSUDRABfT18pCOYwc2GE=
|
||||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230429144221-925a1e7659e6/go.mod h1:3rxYc4HtVcSG9gVaTs2GEBdehh+sYPOwKtyUWEOTb80=
|
||||||
|
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
|
||||||
|
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
||||||
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
|
google.golang.org/grpc v1.58.1 h1:OL+Vz23DTtrrldqHK49FUOPHyY75rvFqJfXC84NYW58=
|
||||||
|
@ -4,14 +4,28 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
ipcRpc "net/rpc"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ipc"
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/what8words"
|
"github.com/tim-beatham/wgmesh/pkg/what8words"
|
||||||
)
|
)
|
||||||
|
|
||||||
// routesToApiRoute: convert the returned type to a JSON object
|
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
||||||
|
|
||||||
|
type ApiServer interface {
|
||||||
|
GetMeshes(c *gin.Context)
|
||||||
|
Run(addr string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type SmegServer struct {
|
||||||
|
router *gin.Engine
|
||||||
|
client *ipcRpc.Client
|
||||||
|
words *what8words.What8Words
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SmegServer) routeToApiRoute(meshNode ctrlserver.MeshNode) []Route {
|
func (s *SmegServer) routeToApiRoute(meshNode ctrlserver.MeshNode) []Route {
|
||||||
routes := make([]Route, len(meshNode.Routes))
|
routes := make([]Route, len(meshNode.Routes))
|
||||||
|
|
||||||
@ -30,7 +44,6 @@ func (s *SmegServer) routeToApiRoute(meshNode ctrlserver.MeshNode) []Route {
|
|||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
// meshNodeToAPImeshNode: convert daemon node to a JSON node
|
|
||||||
func (s *SmegServer) meshNodeToAPIMeshNode(meshNode ctrlserver.MeshNode) *SmegNode {
|
func (s *SmegServer) meshNodeToAPIMeshNode(meshNode ctrlserver.MeshNode) *SmegNode {
|
||||||
if meshNode.Routes == nil {
|
if meshNode.Routes == nil {
|
||||||
meshNode.Routes = make([]ctrlserver.MeshRoute, 0)
|
meshNode.Routes = make([]ctrlserver.MeshRoute, 0)
|
||||||
@ -61,7 +74,6 @@ func (s *SmegServer) meshNodeToAPIMeshNode(meshNode ctrlserver.MeshNode) *SmegNo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// meshToAPIMesh: Convert daemon mesh network to a JSON mesh network
|
|
||||||
func (s *SmegServer) meshToAPIMesh(meshId string, nodes []ctrlserver.MeshNode) SmegMesh {
|
func (s *SmegServer) meshToAPIMesh(meshId string, nodes []ctrlserver.MeshNode) SmegMesh {
|
||||||
var smegMesh SmegMesh
|
var smegMesh SmegMesh
|
||||||
smegMesh.MeshId = meshId
|
smegMesh.MeshId = meshId
|
||||||
@ -74,25 +86,6 @@ func (s *SmegServer) meshToAPIMesh(meshId string, nodes []ctrlserver.MeshNode) S
|
|||||||
return smegMesh
|
return smegMesh
|
||||||
}
|
}
|
||||||
|
|
||||||
// putAlias: place an alias in the mesh
|
|
||||||
func (s *SmegServer) putAlias(meshId, alias string) error {
|
|
||||||
var reply string
|
|
||||||
|
|
||||||
return s.client.PutAlias(ipc.PutAliasArgs{
|
|
||||||
Alias: alias,
|
|
||||||
MeshId: meshId,
|
|
||||||
}, &reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *SmegServer) putDescription(meshId, description string) error {
|
|
||||||
var reply string
|
|
||||||
|
|
||||||
return s.client.PutDescription(ipc.PutDescriptionArgs{
|
|
||||||
Description: description,
|
|
||||||
MeshId: meshId,
|
|
||||||
}, &reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateMesh: creates a mesh network
|
// CreateMesh: creates a mesh network
|
||||||
func (s *SmegServer) CreateMesh(c *gin.Context) {
|
func (s *SmegServer) CreateMesh(c *gin.Context) {
|
||||||
var createMesh CreateMeshRequest
|
var createMesh CreateMeshRequest
|
||||||
@ -105,21 +98,15 @@ func (s *SmegServer) CreateMesh(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%+v\n", createMesh)
|
|
||||||
|
|
||||||
ipcRequest := ipc.NewMeshArgs{
|
ipcRequest := ipc.NewMeshArgs{
|
||||||
WgArgs: ipc.WireGuardArgs{
|
WgArgs: ipc.WireGuardArgs{
|
||||||
WgPort: createMesh.WgPort,
|
WgPort: createMesh.WgPort,
|
||||||
Role: createMesh.Role,
|
|
||||||
Endpoint: createMesh.PublicEndpoint,
|
|
||||||
AdvertiseRoutes: createMesh.AdvertiseRoutes,
|
|
||||||
AdvertiseDefaultRoute: createMesh.AdvertiseDefaults,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
err := s.client.CreateMesh(&ipcRequest, &reply)
|
err := s.client.Call("IpcHandler.CreateMesh", &ipcRequest, &reply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, &gin.H{
|
c.JSON(http.StatusBadRequest, &gin.H{
|
||||||
@ -128,14 +115,6 @@ func (s *SmegServer) CreateMesh(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if createMesh.Alias != "" {
|
|
||||||
s.putAlias(reply, createMesh.Alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
if createMesh.Description != "" {
|
|
||||||
s.putDescription(reply, createMesh.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, &gin.H{
|
c.JSON(http.StatusOK, &gin.H{
|
||||||
"meshid": reply,
|
"meshid": reply,
|
||||||
})
|
})
|
||||||
@ -153,20 +132,16 @@ func (s *SmegServer) JoinMesh(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ipcRequest := ipc.JoinMeshArgs{
|
ipcRequest := ipc.JoinMeshArgs{
|
||||||
MeshId: joinMesh.MeshId,
|
MeshId: joinMesh.MeshId,
|
||||||
IpAddress: joinMesh.Bootstrap,
|
IpAdress: joinMesh.Bootstrap,
|
||||||
WgArgs: ipc.WireGuardArgs{
|
WgArgs: ipc.WireGuardArgs{
|
||||||
WgPort: joinMesh.WgPort,
|
WgPort: joinMesh.WgPort,
|
||||||
Endpoint: joinMesh.PublicEndpoint,
|
|
||||||
Role: joinMesh.Role,
|
|
||||||
AdvertiseRoutes: joinMesh.AdvertiseRoutes,
|
|
||||||
AdvertiseDefaultRoute: joinMesh.AdvertiseDefaults,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
err := s.client.JoinMesh(ipcRequest, &reply)
|
err := s.client.Call("IpcHandler.JoinMesh", &ipcRequest, &reply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, &gin.H{
|
c.JSON(http.StatusBadRequest, &gin.H{
|
||||||
@ -175,14 +150,6 @@ func (s *SmegServer) JoinMesh(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if joinMesh.Alias != "" {
|
|
||||||
s.putAlias(reply, joinMesh.Alias)
|
|
||||||
}
|
|
||||||
|
|
||||||
if joinMesh.Description != "" {
|
|
||||||
s.putDescription(reply, joinMesh.Description)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, &gin.H{
|
c.JSON(http.StatusOK, &gin.H{
|
||||||
"status": "success",
|
"status": "success",
|
||||||
})
|
})
|
||||||
@ -197,7 +164,7 @@ func (s *SmegServer) GetMesh(c *gin.Context) {
|
|||||||
|
|
||||||
getMeshReply := new(ipc.GetMeshReply)
|
getMeshReply := new(ipc.GetMeshReply)
|
||||||
|
|
||||||
err := s.client.GetMesh(meshid, getMeshReply)
|
err := s.client.Call("IpcHandler.GetMesh", &meshid, &getMeshReply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusNotFound,
|
c.JSON(http.StatusNotFound,
|
||||||
@ -212,12 +179,10 @@ func (s *SmegServer) GetMesh(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, mesh)
|
c.JSON(http.StatusOK, mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMeshes: return all the mesh networks that the
|
|
||||||
// user is a part of
|
|
||||||
func (s *SmegServer) GetMeshes(c *gin.Context) {
|
func (s *SmegServer) GetMeshes(c *gin.Context) {
|
||||||
listMeshesReply := new(ipc.ListMeshReply)
|
listMeshesReply := new(ipc.ListMeshReply)
|
||||||
|
|
||||||
err := s.client.ListMeshes(listMeshesReply)
|
err := s.client.Call("IpcHandler.ListMeshes", "", &listMeshesReply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log.WriteErrorf(err.Error())
|
logging.Log.WriteErrorf(err.Error())
|
||||||
@ -230,7 +195,7 @@ func (s *SmegServer) GetMeshes(c *gin.Context) {
|
|||||||
for _, mesh := range listMeshesReply.Meshes {
|
for _, mesh := range listMeshesReply.Meshes {
|
||||||
getMeshReply := new(ipc.GetMeshReply)
|
getMeshReply := new(ipc.GetMeshReply)
|
||||||
|
|
||||||
err := s.client.GetMesh(mesh, getMeshReply)
|
err := s.client.Call("IpcHandler.GetMesh", &mesh, &getMeshReply)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log.WriteErrorf(err.Error())
|
logging.Log.WriteErrorf(err.Error())
|
||||||
@ -244,16 +209,13 @@ func (s *SmegServer) GetMeshes(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, meshes)
|
c.JSON(http.StatusOK, meshes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run: run the API server
|
|
||||||
func (s *SmegServer) Run(addr string) error {
|
func (s *SmegServer) Run(addr string) error {
|
||||||
logging.Log.WriteInfof("Running API server")
|
logging.Log.WriteInfof("Running API server")
|
||||||
return s.router.Run(addr)
|
return s.router.Run(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSmegServer: creates an instance of a new API server
|
|
||||||
// returns an error if something went wrong
|
|
||||||
func NewSmegServer(conf ApiServerConf) (ApiServer, error) {
|
func NewSmegServer(conf ApiServerConf) (ApiServer, error) {
|
||||||
client, err := ipc.NewClientIpc()
|
client, err := ipcRpc.DialHTTP("unix", SockAddr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -277,19 +239,9 @@ func NewSmegServer(conf ApiServerConf) (ApiServer, error) {
|
|||||||
words: words,
|
words: words,
|
||||||
}
|
}
|
||||||
|
|
||||||
v1 := router.Group("/api/v1")
|
router.GET("/meshes", smegServer.GetMeshes)
|
||||||
{
|
router.GET("/mesh/:meshid", smegServer.GetMesh)
|
||||||
meshes := v1.Group("/meshes")
|
router.POST("/mesh/create", smegServer.CreateMesh)
|
||||||
{
|
router.POST("/mesh/join", smegServer.JoinMesh)
|
||||||
meshes.GET("/", smegServer.GetMeshes)
|
|
||||||
}
|
|
||||||
mesh := v1.Group("/mesh")
|
|
||||||
{
|
|
||||||
mesh.GET("/:meshid", smegServer.GetMesh)
|
|
||||||
mesh.POST("/create", smegServer.CreateMesh)
|
|
||||||
mesh.POST("/join", smegServer.JoinMesh)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return smegServer, nil
|
return smegServer, nil
|
||||||
}
|
}
|
||||||
|
122
pkg/api/types.go
122
pkg/api/types.go
@ -1,129 +1,47 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import "time"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ipc"
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/what8words"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Route is an advertised route in the data store
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
// Prefix is the advertised route prefix
|
Prefix string `json:"prefix"`
|
||||||
Prefix string `json:"prefix"`
|
Path []string `json:"path"`
|
||||||
// Path is the hops the destination
|
|
||||||
Path []string `json:"path"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SmegStats is the WireGuard stats that the underlying host
|
|
||||||
// has sent to the peer
|
|
||||||
type SmegStats struct {
|
type SmegStats struct {
|
||||||
// TotalTransmit number of bytes sent to the peer
|
TotalTransmit int64 `json:"totalTransmit"`
|
||||||
TotalTransmit int64 `json:"totalTransmit"`
|
TotalReceived int64 `json:"totalReceived"`
|
||||||
// TotalReceived number of bytes received from the peer
|
|
||||||
TotalReceived int64 `json:"totalReceived"`
|
|
||||||
// KeepAliveInterval WireGuard keepalive interval that is sent to the host
|
|
||||||
KeepAliveInterval time.Duration `json:"keepaliveInterval"`
|
KeepAliveInterval time.Duration `json:"keepaliveInterval"`
|
||||||
// AllowsIps is the allowed path to the destination
|
AllowedIps []string `json:"allowedIps"`
|
||||||
AllowedIps []string `json:"allowedIps"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SmegNode is a node in the mesh network
|
|
||||||
type SmegNode struct {
|
type SmegNode struct {
|
||||||
// Alias is the human readable name that the node is assocaited with
|
Alias string `json:"alias"`
|
||||||
Alias string `json:"alias"`
|
WgHost string `json:"wgHost"`
|
||||||
// WgHost is the WireGuard IP address of the node. This is an IPv6
|
WgEndpoint string `json:"wgEndpoint"`
|
||||||
// address
|
Endpoint string `json:"endpoint"`
|
||||||
WgHost string `json:"wgHost"`
|
Timestamp int `json:"timestamp"`
|
||||||
// WgEndpoint is the physical endpoint of the host that packets
|
Description string `json:"description"`
|
||||||
// are forwarded to
|
PublicKey string `json:"publicKey"`
|
||||||
WgEndpoint string `json:"wgEndpoint"`
|
Routes []Route `json:"routes"`
|
||||||
// Endpoint is the control plane endpoint of the host which
|
Services map[string]string `json:"services"`
|
||||||
// grpc connections are to be sent along
|
Stats SmegStats `json:"stats"`
|
||||||
Endpoint string `json:"endpoint"`
|
|
||||||
// Timestamp is the last time the signified it was alive.
|
|
||||||
// if the node is the leader this is evert heartBeatInterval
|
|
||||||
// otherwise this is the time the node joined the network
|
|
||||||
Timestamp int `json:"timestamp"`
|
|
||||||
// Description is the human readable description of the node
|
|
||||||
Description string `json:"description"`
|
|
||||||
// PublicKey is the WireGuard public key of the node
|
|
||||||
PublicKey string `json:"publicKey"`
|
|
||||||
// Routes is the routes that the node is advertising
|
|
||||||
Routes []Route `json:"routes"`
|
|
||||||
// Services is information about services that the node offers
|
|
||||||
Services map[string]string `json:"services"`
|
|
||||||
// Stats is the WireGuard stats of the node (if any)
|
|
||||||
Stats SmegStats `json:"stats"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SmegMesh encapsulates a single mesh in the API
|
|
||||||
type SmegMesh struct {
|
type SmegMesh struct {
|
||||||
// MeshId is the mesh id of the network
|
MeshId string `json:"meshid"`
|
||||||
MeshId string `json:"meshid"`
|
Nodes map[string]SmegNode `json:"nodes"`
|
||||||
// Nodes is the nodes in the network keyed by their public
|
|
||||||
// key
|
|
||||||
Nodes map[string]SmegNode `json:"nodes"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMeshRequest encapsulates a request to create a mesh network
|
|
||||||
type CreateMeshRequest struct {
|
type CreateMeshRequest struct {
|
||||||
// WgPort is the WireGuard to create the mesh in
|
|
||||||
WgPort int `json:"port" binding:"omitempty,gte=1024,lt=65535"`
|
WgPort int `json:"port" binding:"omitempty,gte=1024,lt=65535"`
|
||||||
// Role is the role to take on in the mesh
|
|
||||||
Role string `json:"role" binding:"required,eq=client|eq=peer"`
|
|
||||||
// AdvertiseRoutes: advertise thi mesh to other meshes
|
|
||||||
AdvertiseRoutes bool `json:"advertiseRoutes"`
|
|
||||||
// AdvertiseDefaults: advertise an exit point
|
|
||||||
AdvertiseDefaults bool `json:"advertiseDefaults"`
|
|
||||||
// Alias: alias of the node in the mesh
|
|
||||||
Alias string `json:"alias"`
|
|
||||||
// Description: description of the node in the mesh
|
|
||||||
Description string `json:"description"`
|
|
||||||
// PublicEndpoint: an alternative public endpoint to advertise
|
|
||||||
PublicEndpoint string `json:"publicEndpoint"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinMeshRequests encapsulates a request to create a mesh network
|
|
||||||
type JoinMeshRequest struct {
|
type JoinMeshRequest struct {
|
||||||
// WgPort is the WireGuard port to run the service on
|
WgPort int `json:"port" binding:"omitempty,gte=1024,lt=65535"`
|
||||||
WgPort int `json:"port" binding:"omitempty,gte=1024,lt=65535"`
|
|
||||||
// Bootstrap is a bootstrap node to use to join the network
|
|
||||||
Bootstrap string `json:"bootstrap" binding:"required"`
|
Bootstrap string `json:"bootstrap" binding:"required"`
|
||||||
// MeshId is the ID of the mesh to join
|
MeshId string `json:"meshid" binding:"required"`
|
||||||
MeshId string `json:"meshid" binding:"required"`
|
|
||||||
// Role is the role to take on in the mesh
|
|
||||||
Role string `json:"role" binding:"required,eq=client|eq=peer"`
|
|
||||||
// AdvertiseRoutes: advertise thi mesh to other meshes
|
|
||||||
AdvertiseRoutes bool `json:"advertiseRoutes"`
|
|
||||||
// AdvertiseDefaults: advertise an exit point
|
|
||||||
AdvertiseDefaults bool `json:"advertiseDefaults"`
|
|
||||||
// Alias: alias of the node in the mesh
|
|
||||||
Alias string `json:"alias"`
|
|
||||||
// Description: description of the node in the mesh
|
|
||||||
Description string `json:"description"`
|
|
||||||
// PublicEndpoint: an alternative public endpoint to advertise
|
|
||||||
PublicEndpoint string `json:"publicEndpoint"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApiServerConf configuration to instantiate the API server
|
|
||||||
type ApiServerConf struct {
|
type ApiServerConf struct {
|
||||||
// WordsFile to use to map IP to words
|
|
||||||
WordsFile string
|
WordsFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SmegSever is the GIN api server that runs the service
|
|
||||||
type SmegServer struct {
|
|
||||||
// gin router to use
|
|
||||||
router *gin.Engine
|
|
||||||
// client to invoke operations
|
|
||||||
client *ipc.SmegmeshIpc
|
|
||||||
// what8words to use to convert IP to an alias
|
|
||||||
words *what8words.What8Words
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApiSever absrtacts the API server
|
|
||||||
type ApiServer interface {
|
|
||||||
Run(addr string) error
|
|
||||||
}
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// automerge: package is depracated and unused. Please refer to crdt
|
|
||||||
// for crdt operations in the mesh
|
|
||||||
package automerge
|
package automerge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -11,36 +9,26 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/automerge/automerge-go"
|
"github.com/automerge/automerge-go"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CrdtMeshManager manage the CRDT datastore
|
// CrdtMeshManager manages nodes in the crdt mesh
|
||||||
type CrdtMeshManager struct {
|
type CrdtMeshManager struct {
|
||||||
// MeshID of the mesh the datastore represents
|
MeshId string
|
||||||
MeshId string
|
IfName string
|
||||||
// IfName: corresponding ifName
|
Client *wgctrl.Client
|
||||||
IfName string
|
doc *automerge.Doc
|
||||||
// Client: corresponding wireguard control client
|
LastHash automerge.ChangeHash
|
||||||
Client *wgctrl.Client
|
conf *conf.WgConfiguration
|
||||||
// doc: autommerge document
|
cache *MeshCrdt
|
||||||
doc *automerge.Doc
|
|
||||||
// LastHash: last hash that the changes were made to
|
|
||||||
LastHash automerge.ChangeHash
|
|
||||||
// conf: WireGuard configuration
|
|
||||||
conf *conf.WgConfiguration
|
|
||||||
// cache: stored cache of the list automerge document
|
|
||||||
// so that the store does not have to be repopulated each time
|
|
||||||
cache *MeshCrdt
|
|
||||||
// lastCachehash: hash of when the document was last changed
|
|
||||||
lastCacheHash automerge.ChangeHash
|
lastCacheHash automerge.ChangeHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddNode as a node to the datastore
|
|
||||||
func (c *CrdtMeshManager) AddNode(node mesh.MeshNode) {
|
func (c *CrdtMeshManager) AddNode(node mesh.MeshNode) {
|
||||||
crdt, ok := node.(*MeshNodeCrdt)
|
crdt, ok := node.(*MeshNodeCrdt)
|
||||||
|
|
||||||
@ -59,7 +47,6 @@ func (c *CrdtMeshManager) AddNode(node mesh.MeshNode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isPeer: returns true if the given node has type peer
|
|
||||||
func (c *CrdtMeshManager) isPeer(nodeId string) bool {
|
func (c *CrdtMeshManager) isPeer(nodeId string) bool {
|
||||||
node, err := c.doc.Path("nodes").Map().Get(nodeId)
|
node, err := c.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -77,8 +64,7 @@ func (c *CrdtMeshManager) isPeer(nodeId string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// isAlive: checks that the node's configuration has been updated
|
// isAlive: checks that the node's configuration has been updated
|
||||||
// since the rquired keep alive time. Depracated no longer works
|
// since the rquired keep alive time
|
||||||
// due to changes in approach
|
|
||||||
func (c *CrdtMeshManager) isAlive(nodeId string) bool {
|
func (c *CrdtMeshManager) isAlive(nodeId string) bool {
|
||||||
node, err := c.doc.Path("nodes").Map().Get(nodeId)
|
node, err := c.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -92,11 +78,10 @@ func (c *CrdtMeshManager) isAlive(nodeId string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// return (time.Now().Unix() - keepAliveTime) < int64(c.conf.DeadTime)
|
|
||||||
return true
|
return true
|
||||||
|
// return (time.Now().Unix() - keepAliveTime) < int64(c.conf.DeadTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPeers: get all the peers in the mesh
|
|
||||||
func (c *CrdtMeshManager) GetPeers() []string {
|
func (c *CrdtMeshManager) GetPeers() []string {
|
||||||
keys, _ := c.doc.Path("nodes").Map().Keys()
|
keys, _ := c.doc.Path("nodes").Map().Keys()
|
||||||
|
|
||||||
@ -107,7 +92,7 @@ func (c *CrdtMeshManager) GetPeers() []string {
|
|||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMesh: Converts the document into a mesh network
|
// GetMesh(): Converts the document into a struct
|
||||||
func (c *CrdtMeshManager) GetMesh() (mesh.MeshSnapshot, error) {
|
func (c *CrdtMeshManager) GetMesh() (mesh.MeshSnapshot, error) {
|
||||||
changes, err := c.doc.Changes(c.lastCacheHash)
|
changes, err := c.doc.Changes(c.lastCacheHash)
|
||||||
|
|
||||||
@ -129,7 +114,7 @@ func (c *CrdtMeshManager) GetMesh() (mesh.MeshSnapshot, error) {
|
|||||||
return c.cache, nil
|
return c.cache, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMeshId: returns the meshid of the mesh
|
// GetMeshId returns the meshid of the mesh
|
||||||
func (c *CrdtMeshManager) GetMeshId() string {
|
func (c *CrdtMeshManager) GetMeshId() string {
|
||||||
return c.MeshId
|
return c.MeshId
|
||||||
}
|
}
|
||||||
@ -150,8 +135,6 @@ func (c *CrdtMeshManager) Load(bytes []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCrdtNodeManagerParams: params to instantiate a new automerge
|
|
||||||
// datastore
|
|
||||||
type NewCrdtNodeMangerParams struct {
|
type NewCrdtNodeMangerParams struct {
|
||||||
MeshId string
|
MeshId string
|
||||||
DevName string
|
DevName string
|
||||||
@ -160,7 +143,7 @@ type NewCrdtNodeMangerParams struct {
|
|||||||
Client *wgctrl.Client
|
Client *wgctrl.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCrdtNodeManager: Create a new automerge crdt data store
|
// NewCrdtNodeManager: Create a new crdt node manager
|
||||||
func NewCrdtNodeManager(params *NewCrdtNodeMangerParams) (*CrdtMeshManager, error) {
|
func NewCrdtNodeManager(params *NewCrdtNodeMangerParams) (*CrdtMeshManager, error) {
|
||||||
var manager CrdtMeshManager
|
var manager CrdtMeshManager
|
||||||
manager.MeshId = params.MeshId
|
manager.MeshId = params.MeshId
|
||||||
@ -172,13 +155,12 @@ func NewCrdtNodeManager(params *NewCrdtNodeMangerParams) (*CrdtMeshManager, erro
|
|||||||
return &manager, nil
|
return &manager, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeExists: returns true if the node exists other returns false
|
// NodeExists: returns true if the node exists. Returns false
|
||||||
func (m *CrdtMeshManager) NodeExists(key string) bool {
|
func (m *CrdtMeshManager) NodeExists(key string) bool {
|
||||||
node, err := m.doc.Path("nodes").Map().Get(key)
|
node, err := m.doc.Path("nodes").Map().Get(key)
|
||||||
return node.Kind() == automerge.KindMap && err == nil
|
return node.Kind() == automerge.KindMap && err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNode: gets a node from the mesh network.
|
|
||||||
func (m *CrdtMeshManager) GetNode(endpoint string) (mesh.MeshNode, error) {
|
func (m *CrdtMeshManager) GetNode(endpoint string) (mesh.MeshNode, error) {
|
||||||
node, err := m.doc.Path("nodes").Map().Get(endpoint)
|
node, err := m.doc.Path("nodes").Map().Get(endpoint)
|
||||||
|
|
||||||
@ -199,12 +181,10 @@ func (m *CrdtMeshManager) GetNode(endpoint string) (mesh.MeshNode, error) {
|
|||||||
return meshNode, nil
|
return meshNode, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Length: returns the number of nodes in the store
|
|
||||||
func (m *CrdtMeshManager) Length() int {
|
func (m *CrdtMeshManager) Length() int {
|
||||||
return m.doc.Path("nodes").Map().Len()
|
return m.doc.Path("nodes").Map().Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDevice: get the underlying WireGuard device
|
|
||||||
func (m *CrdtMeshManager) GetDevice() (*wgtypes.Device, error) {
|
func (m *CrdtMeshManager) GetDevice() (*wgtypes.Device, error) {
|
||||||
dev, err := m.Client.Device(m.IfName)
|
dev, err := m.Client.Device(m.IfName)
|
||||||
|
|
||||||
@ -215,7 +195,7 @@ func (m *CrdtMeshManager) GetDevice() (*wgtypes.Device, error) {
|
|||||||
return dev, nil
|
return dev, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasChanges: returns true if there are changes since last time synchronised
|
// HasChanges returns true if we have changes since the last time we synced
|
||||||
func (m *CrdtMeshManager) HasChanges() bool {
|
func (m *CrdtMeshManager) HasChanges() bool {
|
||||||
changes, err := m.doc.Changes(m.LastHash)
|
changes, err := m.doc.Changes(m.LastHash)
|
||||||
|
|
||||||
@ -229,7 +209,6 @@ func (m *CrdtMeshManager) HasChanges() bool {
|
|||||||
return len(changes) > 0
|
return len(changes) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveChanges: save changes to the datastore
|
|
||||||
func (m *CrdtMeshManager) SaveChanges() {
|
func (m *CrdtMeshManager) SaveChanges() {
|
||||||
hashes := m.doc.Heads()
|
hashes := m.doc.Heads()
|
||||||
hash := hashes[len(hashes)-1]
|
hash := hashes[len(hashes)-1]
|
||||||
@ -238,7 +217,6 @@ func (m *CrdtMeshManager) SaveChanges() {
|
|||||||
m.LastHash = hash
|
m.LastHash = hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateTimeStamp: updates the timestamp of the document
|
|
||||||
func (m *CrdtMeshManager) UpdateTimeStamp(nodeId string) error {
|
func (m *CrdtMeshManager) UpdateTimeStamp(nodeId string) error {
|
||||||
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -259,7 +237,6 @@ func (m *CrdtMeshManager) UpdateTimeStamp(nodeId string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDescription: set the description of the given node
|
|
||||||
func (m *CrdtMeshManager) SetDescription(nodeId string, description string) error {
|
func (m *CrdtMeshManager) SetDescription(nodeId string, description string) error {
|
||||||
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -280,7 +257,6 @@ func (m *CrdtMeshManager) SetDescription(nodeId string, description string) erro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAlias: set the alias of the given node
|
|
||||||
func (m *CrdtMeshManager) SetAlias(nodeId string, alias string) error {
|
func (m *CrdtMeshManager) SetAlias(nodeId string, alias string) error {
|
||||||
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -301,7 +277,6 @@ func (m *CrdtMeshManager) SetAlias(nodeId string, alias string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddService: add a service to the given node
|
|
||||||
func (m *CrdtMeshManager) AddService(nodeId, key, value string) error {
|
func (m *CrdtMeshManager) AddService(nodeId, key, value string) error {
|
||||||
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -323,7 +298,6 @@ func (m *CrdtMeshManager) AddService(nodeId, key, value string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveService: remove a service from a node
|
|
||||||
func (m *CrdtMeshManager) RemoveService(nodeId, key string) error {
|
func (m *CrdtMeshManager) RemoveService(nodeId, key string) error {
|
||||||
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
node, err := m.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -404,7 +378,6 @@ func (m *CrdtMeshManager) AddRoutes(nodeId string, routes ...mesh.Route) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRoutes: get the routes that the given node is directly advertising
|
|
||||||
func (m *CrdtMeshManager) getRoutes(nodeId string) ([]Route, error) {
|
func (m *CrdtMeshManager) getRoutes(nodeId string) ([]Route, error) {
|
||||||
nodeVal, err := m.doc.Path("nodes").Map().Get(nodeId)
|
nodeVal, err := m.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -431,8 +404,6 @@ func (m *CrdtMeshManager) getRoutes(nodeId string) ([]Route, error) {
|
|||||||
return lib.MapValues(routes), err
|
return lib.MapValues(routes), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRoutes: get all the routes that the node can see. The routes that the node
|
|
||||||
// can say may not be direct but cann also be indirect
|
|
||||||
func (m *CrdtMeshManager) GetRoutes(targetNode string) (map[string]mesh.Route, error) {
|
func (m *CrdtMeshManager) GetRoutes(targetNode string) (map[string]mesh.Route, error) {
|
||||||
node, err := m.GetNode(targetNode)
|
node, err := m.GetNode(targetNode)
|
||||||
|
|
||||||
@ -476,13 +447,12 @@ func (m *CrdtMeshManager) GetRoutes(targetNode string) (map[string]mesh.Route, e
|
|||||||
return routes, nil
|
return routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveNode: removes a node from the datastore
|
|
||||||
func (m *CrdtMeshManager) RemoveNode(nodeId string) error {
|
func (m *CrdtMeshManager) RemoveNode(nodeId string) error {
|
||||||
err := m.doc.Path("nodes").Map().Delete(nodeId)
|
err := m.doc.Path("nodes").Map().Delete(nodeId)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveRoutes: withdraw all the routes the nodeID is advertising
|
// DeleteRoutes deletes the specified routes
|
||||||
func (m *CrdtMeshManager) RemoveRoutes(nodeId string, routes ...mesh.Route) error {
|
func (m *CrdtMeshManager) RemoveRoutes(nodeId string, routes ...mesh.Route) error {
|
||||||
nodeVal, err := m.doc.Path("nodes").Map().Get(nodeId)
|
nodeVal, err := m.doc.Path("nodes").Map().Get(nodeId)
|
||||||
|
|
||||||
@ -516,37 +486,30 @@ func (m *CrdtMeshManager) GetConfiguration() *conf.WgConfiguration {
|
|||||||
func (m *CrdtMeshManager) Mark(nodeId string) {
|
func (m *CrdtMeshManager) Mark(nodeId string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSyncer: get the bi-directionally syncer to synchronise the document
|
|
||||||
func (m *CrdtMeshManager) GetSyncer() mesh.MeshSyncer {
|
func (m *CrdtMeshManager) GetSyncer() mesh.MeshSyncer {
|
||||||
return NewAutomergeSync(m)
|
return NewAutomergeSync(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prune: prune all dead nodes
|
|
||||||
func (m *CrdtMeshManager) Prune() error {
|
func (m *CrdtMeshManager) Prune() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare: compare two mesh node for equality
|
|
||||||
func (m1 *MeshNodeCrdt) Compare(m2 *MeshNodeCrdt) int {
|
func (m1 *MeshNodeCrdt) Compare(m2 *MeshNodeCrdt) int {
|
||||||
return strings.Compare(m1.PublicKey, m2.PublicKey)
|
return strings.Compare(m1.PublicKey, m2.PublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHostEndpoint: get the ctrl endpoint of the host
|
|
||||||
func (m *MeshNodeCrdt) GetHostEndpoint() string {
|
func (m *MeshNodeCrdt) GetHostEndpoint() string {
|
||||||
return m.HostEndpoint
|
return m.HostEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPublicKey: get the public key of the node
|
|
||||||
func (m *MeshNodeCrdt) GetPublicKey() (wgtypes.Key, error) {
|
func (m *MeshNodeCrdt) GetPublicKey() (wgtypes.Key, error) {
|
||||||
return wgtypes.ParseKey(m.PublicKey)
|
return wgtypes.ParseKey(m.PublicKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWgEndpoint: get the outer WireGuard endpoint
|
|
||||||
func (m *MeshNodeCrdt) GetWgEndpoint() string {
|
func (m *MeshNodeCrdt) GetWgEndpoint() string {
|
||||||
return m.WgEndpoint
|
return m.WgEndpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetWgHost: get the WireGuard IP address of the host
|
|
||||||
func (m *MeshNodeCrdt) GetWgHost() *net.IPNet {
|
func (m *MeshNodeCrdt) GetWgHost() *net.IPNet {
|
||||||
_, ipnet, err := net.ParseCIDR(m.WgHost)
|
_, ipnet, err := net.ParseCIDR(m.WgHost)
|
||||||
|
|
||||||
@ -557,12 +520,10 @@ func (m *MeshNodeCrdt) GetWgHost() *net.IPNet {
|
|||||||
return ipnet
|
return ipnet
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTimeStamp: get timestamp if when the node was last updated
|
|
||||||
func (m *MeshNodeCrdt) GetTimeStamp() int64 {
|
func (m *MeshNodeCrdt) GetTimeStamp() int64 {
|
||||||
return m.Timestamp
|
return m.Timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRoutes: get all the routes advertised by the node
|
|
||||||
func (m *MeshNodeCrdt) GetRoutes() []mesh.Route {
|
func (m *MeshNodeCrdt) GetRoutes() []mesh.Route {
|
||||||
return lib.Map(lib.MapValues(m.Routes), func(r Route) mesh.Route {
|
return lib.Map(lib.MapValues(m.Routes), func(r Route) mesh.Route {
|
||||||
return &Route{
|
return &Route{
|
||||||
@ -572,12 +533,10 @@ func (m *MeshNodeCrdt) GetRoutes() []mesh.Route {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDescription: get the description of the node
|
|
||||||
func (m *MeshNodeCrdt) GetDescription() string {
|
func (m *MeshNodeCrdt) GetDescription() string {
|
||||||
return m.Description
|
return m.Description
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetIdentifier: get the iderntifier section of the ipv6 address
|
|
||||||
func (m *MeshNodeCrdt) GetIdentifier() string {
|
func (m *MeshNodeCrdt) GetIdentifier() string {
|
||||||
ipv6 := m.WgHost[:len(m.WgHost)-4]
|
ipv6 := m.WgHost[:len(m.WgHost)-4]
|
||||||
|
|
||||||
@ -586,12 +545,10 @@ func (m *MeshNodeCrdt) GetIdentifier() string {
|
|||||||
return strings.Join(constituents, ":")
|
return strings.Join(constituents, ":")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAlias: get the alias of the node
|
|
||||||
func (m *MeshNodeCrdt) GetAlias() string {
|
func (m *MeshNodeCrdt) GetAlias() string {
|
||||||
return m.Alias
|
return m.Alias
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetServices: get all the services the node is advertising
|
|
||||||
func (m *MeshNodeCrdt) GetServices() map[string]string {
|
func (m *MeshNodeCrdt) GetServices() map[string]string {
|
||||||
services := make(map[string]string)
|
services := make(map[string]string)
|
||||||
|
|
||||||
@ -608,7 +565,6 @@ func (n *MeshNodeCrdt) GetType() conf.NodeType {
|
|||||||
return conf.NodeType(n.Type)
|
return conf.NodeType(n.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNodes: get all the nodes in the network
|
|
||||||
func (m *MeshCrdt) GetNodes() map[string]mesh.MeshNode {
|
func (m *MeshCrdt) GetNodes() map[string]mesh.MeshNode {
|
||||||
nodes := make(map[string]mesh.MeshNode)
|
nodes := make(map[string]mesh.MeshNode)
|
||||||
|
|
||||||
@ -630,18 +586,15 @@ func (m *MeshCrdt) GetNodes() map[string]mesh.MeshNode {
|
|||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDestination: get destination of the route
|
|
||||||
func (r *Route) GetDestination() *net.IPNet {
|
func (r *Route) GetDestination() *net.IPNet {
|
||||||
_, ipnet, _ := net.ParseCIDR(r.Destination)
|
_, ipnet, _ := net.ParseCIDR(r.Destination)
|
||||||
return ipnet
|
return ipnet
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHopCount: get the number of hops to the destination
|
|
||||||
func (r *Route) GetHopCount() int {
|
func (r *Route) GetHopCount() int {
|
||||||
return len(r.Path)
|
return len(r.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPath: get the total path which includes the number of hops
|
|
||||||
func (r *Route) GetPath() []string {
|
func (r *Route) GetPath() []string {
|
||||||
return r.Path
|
return r.Path
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,15 @@
|
|||||||
// automerge: automerge is a CRDT library. Defines a CRDT
|
|
||||||
// datastore and methods to resolve conflicts
|
|
||||||
package automerge
|
package automerge
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/automerge/automerge-go"
|
"github.com/automerge/automerge-go"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AutomergeSync: defines a synchroniser to bi-directionally synchronise the
|
|
||||||
// two states
|
|
||||||
type AutomergeSync struct {
|
type AutomergeSync struct {
|
||||||
// state: the automerge sync state to use
|
state *automerge.SyncState
|
||||||
state *automerge.SyncState
|
|
||||||
// manager: the corresponding data store that we are merging
|
|
||||||
manager *CrdtMeshManager
|
manager *CrdtMeshManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateMessage: geenrate a new automerge message to synchronise
|
|
||||||
// returns a byte of the message and a boolean of whether or not there
|
|
||||||
// are more messages in the sequence
|
|
||||||
func (a *AutomergeSync) GenerateMessage() ([]byte, bool) {
|
func (a *AutomergeSync) GenerateMessage() ([]byte, bool) {
|
||||||
msg, valid := a.state.GenerateMessage()
|
msg, valid := a.state.GenerateMessage()
|
||||||
|
|
||||||
@ -29,8 +20,6 @@ func (a *AutomergeSync) GenerateMessage() ([]byte, bool) {
|
|||||||
return msg.Bytes(), true
|
return msg.Bytes(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
// RecvMessage: receive an automerge message to merge in the datastore
|
|
||||||
// returns an error if unsuccessful
|
|
||||||
func (a *AutomergeSync) RecvMessage(msg []byte) error {
|
func (a *AutomergeSync) RecvMessage(msg []byte) error {
|
||||||
_, err := a.state.ReceiveMessage(msg)
|
_, err := a.state.ReceiveMessage(msg)
|
||||||
|
|
||||||
@ -41,13 +30,11 @@ func (a *AutomergeSync) RecvMessage(msg []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete: complete the synchronisation process
|
|
||||||
func (a *AutomergeSync) Complete() {
|
func (a *AutomergeSync) Complete() {
|
||||||
logging.Log.WriteInfof("sync completed")
|
logging.Log.WriteInfof("Sync Completed")
|
||||||
a.manager.SaveChanges()
|
a.manager.SaveChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAutomergeSync: instantiates a new automerge syncer
|
|
||||||
func NewAutomergeSync(manager *CrdtMeshManager) *AutomergeSync {
|
func NewAutomergeSync(manager *CrdtMeshManager) *AutomergeSync {
|
||||||
return &AutomergeSync{
|
return &AutomergeSync{
|
||||||
state: automerge.NewSyncState(manager.doc),
|
state: automerge.NewSyncState(manager.doc),
|
||||||
|
@ -6,9 +6,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -83,6 +83,7 @@ func TestAddNodeAddRoute(t *testing.T) {
|
|||||||
testParams.manager.AddNode(testNode)
|
testParams.manager.AddNode(testNode)
|
||||||
testParams.manager.AddRoutes(pubKey.String(), &mesh.RouteStub{
|
testParams.manager.AddRoutes(pubKey.String(), &mesh.RouteStub{
|
||||||
Destination: destination,
|
Destination: destination,
|
||||||
|
HopCount: 0,
|
||||||
Path: make([]string, 0),
|
Path: make([]string, 0),
|
||||||
})
|
})
|
||||||
updatedNode, err := testParams.manager.GetNode(pubKey.String())
|
updatedNode, err := testParams.manager.GetNode(pubKey.String())
|
||||||
@ -296,6 +297,7 @@ func TestAddRoutesNodeDoesNotExist(t *testing.T) {
|
|||||||
|
|
||||||
err := testParams.manager.AddRoutes("AAAAA", &mesh.RouteStub{
|
err := testParams.manager.AddRoutes("AAAAA", &mesh.RouteStub{
|
||||||
Destination: destination,
|
Destination: destination,
|
||||||
|
HopCount: 0,
|
||||||
Path: make([]string, 0),
|
Path: make([]string, 0),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -3,16 +3,13 @@ package automerge
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CrdtProviderFactory: abstracts the instantiation of an automerge
|
|
||||||
// datastore
|
|
||||||
type CrdtProviderFactory struct{}
|
type CrdtProviderFactory struct{}
|
||||||
|
|
||||||
// CreateMesh: create a new mesh datastore
|
|
||||||
func (f *CrdtProviderFactory) CreateMesh(params *mesh.MeshProviderFactoryParams) (mesh.MeshProvider, error) {
|
func (f *CrdtProviderFactory) CreateMesh(params *mesh.MeshProviderFactoryParams) (mesh.MeshProvider, error) {
|
||||||
return NewCrdtNodeManager(&NewCrdtNodeMangerParams{
|
return NewCrdtNodeManager(&NewCrdtNodeMangerParams{
|
||||||
MeshId: params.MeshId,
|
MeshId: params.MeshId,
|
||||||
@ -22,12 +19,11 @@ func (f *CrdtProviderFactory) CreateMesh(params *mesh.MeshProviderFactoryParams)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeshNodeFactory: abstracts the instnatiation of a node
|
|
||||||
type MeshNodeFactory struct {
|
type MeshNodeFactory struct {
|
||||||
Config conf.DaemonConfiguration
|
Config conf.DaemonConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build: builds the mesh node that represents the host machine to add
|
// Build builds the mesh node that represents the host machine to add
|
||||||
// to the mesh
|
// to the mesh
|
||||||
func (f *MeshNodeFactory) Build(params *mesh.MeshNodeFactoryParams) mesh.MeshNode {
|
func (f *MeshNodeFactory) Build(params *mesh.MeshNodeFactoryParams) mesh.MeshNode {
|
||||||
hostName := f.getAddress(params)
|
hostName := f.getAddress(params)
|
||||||
@ -52,7 +48,7 @@ func (f *MeshNodeFactory) Build(params *mesh.MeshNodeFactoryParams) mesh.MeshNod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAddress: returns the routable address of the machine.
|
// getAddress returns the routable address of the machine.
|
||||||
func (f *MeshNodeFactory) getAddress(params *mesh.MeshNodeFactoryParams) string {
|
func (f *MeshNodeFactory) getAddress(params *mesh.MeshNodeFactoryParams) string {
|
||||||
var hostName string = ""
|
var hostName string = ""
|
||||||
|
|
||||||
@ -63,7 +59,7 @@ func (f *MeshNodeFactory) getAddress(params *mesh.MeshNodeFactoryParams) string
|
|||||||
} else {
|
} else {
|
||||||
ipFunc := lib.GetPublicIP
|
ipFunc := lib.GetPublicIP
|
||||||
|
|
||||||
if *params.MeshConfig.IPDiscovery == conf.OUTGOING_IP_DISCOVERY {
|
if *params.MeshConfig.IPDiscovery == conf.DNS_IP_DISCOVERY {
|
||||||
ipFunc = lib.GetOutboundIP
|
ipFunc = lib.GetOutboundIP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CmdRunner: run cmd commands when instantiating a network
|
|
||||||
type CmdRunner interface {
|
type CmdRunner interface {
|
||||||
RunCommands(commands ...string) error
|
RunCommands(commands ...string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnixCmdRunner: Run UNIX commands
|
|
||||||
type UnixCmdRunner struct{}
|
type UnixCmdRunner struct{}
|
||||||
|
|
||||||
// RunCommand: runs the unix command. It splits the command into fields
|
// RunCommand: runs the unix command. It splits the command into fields
|
||||||
@ -22,7 +20,6 @@ func RunCommand(cmd string) error {
|
|||||||
return c.Run()
|
return c.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunCommands: run a series of commands
|
|
||||||
func (l *UnixCmdRunner) RunCommands(commands ...string) error {
|
func (l *UnixCmdRunner) RunCommands(commands ...string) error {
|
||||||
for _, cmd := range commands {
|
for _, cmd := range commands {
|
||||||
err := RunCommand(cmd)
|
err := RunCommand(cmd)
|
||||||
|
@ -8,7 +8,14 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NodeType types of the node either peer or client
|
type WgMeshConfigurationError struct {
|
||||||
|
msg string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WgMeshConfigurationError) Error() string {
|
||||||
|
return m.msg
|
||||||
|
}
|
||||||
|
|
||||||
type NodeType string
|
type NodeType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -16,23 +23,11 @@ const (
|
|||||||
CLIENT_ROLE NodeType = "client"
|
CLIENT_ROLE NodeType = "client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IPDiscovery: what IPDiscovery service to use
|
|
||||||
type IPDiscovery string
|
type IPDiscovery string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Public IP use an IP service to discover your IP
|
|
||||||
PUBLIC_IP_DISCOVERY IPDiscovery = "public"
|
PUBLIC_IP_DISCOVERY IPDiscovery = "public"
|
||||||
// Outgonig: Use your labelled packet IP
|
DNS_IP_DISCOVERY IPDiscovery = "dns"
|
||||||
OUTGOING_IP_DISCOVERY IPDiscovery = "outgoing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Loglevel: what log level to use either error info or warning
|
|
||||||
type LogLevel string
|
|
||||||
|
|
||||||
const (
|
|
||||||
ERROR LogLevel = "error"
|
|
||||||
WARNING LogLevel = "warning"
|
|
||||||
INFO LogLevel = "info"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// WgConfiguration contains per-mesh WireGuard configuration. Contains poitner types only so we can
|
// WgConfiguration contains per-mesh WireGuard configuration. Contains poitner types only so we can
|
||||||
@ -40,7 +35,7 @@ const (
|
|||||||
type WgConfiguration struct {
|
type WgConfiguration struct {
|
||||||
// IPDIscovery: how to discover your IP if not specified. Use your outgoing IP or use a public
|
// IPDIscovery: how to discover your IP if not specified. Use your outgoing IP or use a public
|
||||||
// service for IPDiscoverability
|
// service for IPDiscoverability
|
||||||
IPDiscovery *IPDiscovery `yaml:"ipDiscovery" validate:"required,eq=public|eq=outgoing"`
|
IPDiscovery *IPDiscovery `yaml:"ipDiscovery" validate:"required,eq=public|eq=dns"`
|
||||||
// AdvertiseRoutes: specifies whether the node can act as a router routing packets between meshes
|
// AdvertiseRoutes: specifies whether the node can act as a router routing packets between meshes
|
||||||
AdvertiseRoutes *bool `yaml:"advertiseRoute" validate:"required"`
|
AdvertiseRoutes *bool `yaml:"advertiseRoute" validate:"required"`
|
||||||
// AdvertiseDefaultRoute: specifies whether or not this route should advertise a default route
|
// AdvertiseDefaultRoute: specifies whether or not this route should advertise a default route
|
||||||
@ -52,6 +47,7 @@ type WgConfiguration struct {
|
|||||||
// If the user is globaly accessible they specify themselves as a client.
|
// If the user is globaly accessible they specify themselves as a client.
|
||||||
Role *NodeType `yaml:"role" validate:"required,eq=client|eq=peer"`
|
Role *NodeType `yaml:"role" validate:"required,eq=client|eq=peer"`
|
||||||
// KeepAliveWg configures the implementation so that we send keep alive packets to peers.
|
// KeepAliveWg configures the implementation so that we send keep alive packets to peers.
|
||||||
|
// KeepAlive can only be set if role is type client
|
||||||
KeepAliveWg *int `yaml:"keepAliveWg" validate:"omitempty,gte=0"`
|
KeepAliveWg *int `yaml:"keepAliveWg" validate:"omitempty,gte=0"`
|
||||||
// PreUp are WireGuard commands to run before adding the WG interface
|
// PreUp are WireGuard commands to run before adding the WG interface
|
||||||
PreUp []string `yaml:"preUp"`
|
PreUp []string `yaml:"preUp"`
|
||||||
@ -77,28 +73,26 @@ type DaemonConfiguration struct {
|
|||||||
GrpcPort int `yaml:"gRPCPort" validate:"required"`
|
GrpcPort int `yaml:"gRPCPort" validate:"required"`
|
||||||
// Timeout number of seconds without response that a node is considered unreachable by gRPC
|
// Timeout number of seconds without response that a node is considered unreachable by gRPC
|
||||||
Timeout int `yaml:"timeout" validate:"required,gte=1"`
|
Timeout int `yaml:"timeout" validate:"required,gte=1"`
|
||||||
|
// Profile whether or not to include a http server that profiles the code
|
||||||
|
Profile bool `yaml:"profile"`
|
||||||
// StubWg whether or not to stub the WireGuard types
|
// StubWg whether or not to stub the WireGuard types
|
||||||
StubWg bool `yaml:"stubWg"`
|
StubWg bool `yaml:"stubWg"`
|
||||||
// SyncInterval specifies how long the minimum time should be between synchronisation
|
// SyncRate specifies how long the minimum time should be between synchronisation
|
||||||
SyncInterval int `yaml:"syncInterval" validate:"required,gte=1"`
|
SyncRate int `yaml:"syncRate" validate:"required,gte=1"`
|
||||||
// PullInterval specifies the interval between checking for configuration changes
|
// KeepAliveTime: number of seconds before the leader of the mesh sends an update to
|
||||||
PullInterval int `yaml:"pullInterval" validate:"gte=0"`
|
|
||||||
// Heartbeat: number of seconds before the leader of the mesh sends an update to
|
|
||||||
// send to every member in the mesh
|
// send to every member in the mesh
|
||||||
Heartbeat int `yaml:"heartbeatInterval" validate:"required,gte=1"`
|
KeepAliveTime int `yaml:"keepAliveTime" validate:"required,gte=1"`
|
||||||
// ClusterSize specifies how many neighbours you should synchronise with per round
|
// ClusterSize specifies how many neighbours you should synchronise with per round
|
||||||
ClusterSize int `yaml:"clusterSize" validate:"gte=1"`
|
ClusterSize int `yaml:"clusterSize" validate:"gte=1"`
|
||||||
// InterClusterChance specifies the probabilityof inter-cluster communication in a sync round
|
// InterClusterChance specifies the probabilityof inter-cluster communication in a sync round
|
||||||
InterClusterChance float64 `yaml:"interClusterChance" validate:"gt=0"`
|
InterClusterChance float64 `yaml:"interClusterChance" validate:"gt=0"`
|
||||||
// Branch specifies the number of nodes to synchronise with when a node has
|
// BranchRate specifies the number of nodes to synchronise with when a node has
|
||||||
// new changes to send to the mesh
|
// new changes to send to the mesh
|
||||||
Branch int `yaml:"branch" validate:"required,gte=1"`
|
BranchRate int `yaml:"branchRate" validate:"required,gte=1"`
|
||||||
// InfectionCount: number of time to sync before an update can no longer be 'caught'
|
// InfectionCount: number of time to sync before an update can no longer be 'caught'
|
||||||
InfectionCount int `yaml:"infectionCount" validate:"required,gte=1"`
|
InfectionCount int `yaml:"infectionCount" validate:"required,gte=1"`
|
||||||
// BaseConfiguration base WireGuard configuration to use, this is used when none is provided
|
// BaseConfiguration base WireGuard configuration to use, this is used when none is provided
|
||||||
BaseConfiguration WgConfiguration `yaml:"baseConfiguration" validate:"required"`
|
BaseConfiguration WgConfiguration `yaml:"baseConfiguration" validate:"required"`
|
||||||
// LogLevel specifies the log level to output, defaults is warning
|
|
||||||
LogLevel LogLevel `yaml:"logLevel" validate:"eq=info|eq=warning|eq=error"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValdiateMeshConfiguration: validates the mesh configuration
|
// ValdiateMeshConfiguration: validates the mesh configuration
|
||||||
@ -126,18 +120,9 @@ func ValidateMeshConfiguration(conf *WgConfiguration) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ValidateDaemonConfiguration: validates the dameon configuration that is used.
|
// ValidateDaemonConfiguration: validates the dameon configuration that is used.
|
||||||
func ValidateDaemonConfiguration(conf *DaemonConfiguration) error {
|
func ValidateDaemonConfiguration(c *DaemonConfiguration) error {
|
||||||
if conf.BaseConfiguration.KeepAliveWg == nil {
|
|
||||||
var keepAlive int = 0
|
|
||||||
conf.BaseConfiguration.KeepAliveWg = &keepAlive
|
|
||||||
}
|
|
||||||
|
|
||||||
if conf.LogLevel == "" {
|
|
||||||
conf.LogLevel = WARNING
|
|
||||||
}
|
|
||||||
|
|
||||||
validate := validator.New(validator.WithRequiredStructEnabled())
|
validate := validator.New(validator.WithRequiredStructEnabled())
|
||||||
err := validate.Struct(conf)
|
err := validate.Struct(c)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,6 +142,11 @@ func ParseDaemonConfiguration(filePath string) (*DaemonConfiguration, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.BaseConfiguration.KeepAliveWg == nil {
|
||||||
|
var keepAlive int = 0
|
||||||
|
conf.BaseConfiguration.KeepAliveWg = &keepAlive
|
||||||
|
}
|
||||||
|
|
||||||
return &conf, ValidateDaemonConfiguration(&conf)
|
return &conf, ValidateDaemonConfiguration(&conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@ func getExampleConfiguration() *DaemonConfiguration {
|
|||||||
SkipCertVerification: true,
|
SkipCertVerification: true,
|
||||||
GrpcPort: 25,
|
GrpcPort: 25,
|
||||||
Timeout: 5,
|
Timeout: 5,
|
||||||
|
Profile: false,
|
||||||
StubWg: false,
|
StubWg: false,
|
||||||
SyncInterval: 2,
|
SyncRate: 2,
|
||||||
Heartbeat: 2,
|
KeepAliveTime: 2,
|
||||||
ClusterSize: 64,
|
ClusterSize: 64,
|
||||||
InterClusterChance: 0.15,
|
InterClusterChance: 0.15,
|
||||||
Branch: 3,
|
BranchRate: 3,
|
||||||
PullInterval: 0,
|
|
||||||
InfectionCount: 2,
|
InfectionCount: 2,
|
||||||
BaseConfiguration: WgConfiguration{
|
BaseConfiguration: WgConfiguration{
|
||||||
IPDiscovery: &discovery,
|
IPDiscovery: &discovery,
|
||||||
@ -153,7 +153,7 @@ func TestRoleTypeNotSpecified(t *testing.T) {
|
|||||||
|
|
||||||
func TestBranchRateZero(t *testing.T) {
|
func TestBranchRateZero(t *testing.T) {
|
||||||
conf := getExampleConfiguration()
|
conf := getExampleConfiguration()
|
||||||
conf.Branch = 0
|
conf.BranchRate = 0
|
||||||
|
|
||||||
err := ValidateDaemonConfiguration(conf)
|
err := ValidateDaemonConfiguration(conf)
|
||||||
|
|
||||||
@ -162,9 +162,9 @@ func TestBranchRateZero(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestsyncTimeZero(t *testing.T) {
|
func TestSyncRateZero(t *testing.T) {
|
||||||
conf := getExampleConfiguration()
|
conf := getExampleConfiguration()
|
||||||
conf.SyncInterval = 0
|
conf.SyncRate = 0
|
||||||
|
|
||||||
err := ValidateDaemonConfiguration(conf)
|
err := ValidateDaemonConfiguration(conf)
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ func TestsyncTimeZero(t *testing.T) {
|
|||||||
|
|
||||||
func TestKeepAliveTimeZero(t *testing.T) {
|
func TestKeepAliveTimeZero(t *testing.T) {
|
||||||
conf := getExampleConfiguration()
|
conf := getExampleConfiguration()
|
||||||
conf.Heartbeat = 0
|
conf.KeepAliveTime = 0
|
||||||
err := ValidateDaemonConfiguration(conf)
|
err := ValidateDaemonConfiguration(conf)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -215,17 +215,6 @@ func TestInfectionCountOne(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPullTimeNegative(t *testing.T) {
|
|
||||||
conf := getExampleConfiguration()
|
|
||||||
conf.PullInterval = -1
|
|
||||||
|
|
||||||
err := ValidateDaemonConfiguration(conf)
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
t.Fatal(`error should be thrown`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidConfiguration(t *testing.T) {
|
func TestValidConfiguration(t *testing.T) {
|
||||||
conf := getExampleConfiguration()
|
conf := getExampleConfiguration()
|
||||||
err := ValidateDaemonConfiguration(conf)
|
err := ValidateDaemonConfiguration(conf)
|
||||||
|
@ -7,30 +7,25 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnCluster: splits nodes into clusters where nodes in a cluster communicate
|
// ConnCluster splits nodes into clusters where nodes in a cluster communicate
|
||||||
// frequently and nodes outside of a cluster communicate infrequently
|
// frequently and nodes outside of a cluster communicate infrequently
|
||||||
type ConnCluster interface {
|
type ConnCluster interface {
|
||||||
// Getneighbours: get neighbours of the cluster the node is in
|
|
||||||
GetNeighbours(global []string, selfId string) []string
|
GetNeighbours(global []string, selfId string) []string
|
||||||
// GetInterCluster: get the cluster to communicate with
|
|
||||||
GetInterCluster(global []string, selfId string) string
|
GetInterCluster(global []string, selfId string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConnnClusterImpl: implementation of the connection cluster
|
|
||||||
type ConnClusterImpl struct {
|
type ConnClusterImpl struct {
|
||||||
clusterSize int
|
clusterSize int
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform binary search to attain a size of a group
|
|
||||||
func binarySearch(global []string, selfId string, groupSize int) (int, int) {
|
func binarySearch(global []string, selfId string, groupSize int) (int, int) {
|
||||||
slices.Sort(global)
|
slices.Sort(global)
|
||||||
|
|
||||||
lower := 0
|
lower := 0
|
||||||
higher := len(global) - 1
|
higher := len(global) - 1
|
||||||
|
mid := (lower + higher) / 2
|
||||||
|
|
||||||
for (higher+1)-lower > groupSize {
|
for (higher+1)-lower > groupSize {
|
||||||
mid := (lower + higher) / 2
|
|
||||||
|
|
||||||
if global[mid] < selfId {
|
if global[mid] < selfId {
|
||||||
lower = mid + 1
|
lower = mid + 1
|
||||||
} else if global[mid] > selfId {
|
} else if global[mid] > selfId {
|
||||||
@ -38,12 +33,14 @@ func binarySearch(global []string, selfId string, groupSize int) (int, int) {
|
|||||||
} else {
|
} else {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mid = (lower + higher) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
return lower, int(math.Min(float64(lower+groupSize), float64(len(global))))
|
return lower, int(math.Min(float64(lower+groupSize), float64(len(global))))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNeighbours: return the neighbours 'nearest' to you. In this implementation the
|
// GetNeighbours return the neighbours 'nearest' to you. In this implementation the
|
||||||
// neighbours aren't actually the ones nearest to you but just the ones nearest
|
// neighbours aren't actually the ones nearest to you but just the ones nearest
|
||||||
// to you alphabetically. Perform binary search to get the total group
|
// to you alphabetically. Perform binary search to get the total group
|
||||||
func (i *ConnClusterImpl) GetNeighbours(global []string, selfId string) []string {
|
func (i *ConnClusterImpl) GetNeighbours(global []string, selfId string) []string {
|
||||||
@ -54,7 +51,7 @@ func (i *ConnClusterImpl) GetNeighbours(global []string, selfId string) []string
|
|||||||
return global[lower:higher]
|
return global[lower:higher]
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInterCluster: get nodes not in your cluster. Every round there is a given chance
|
// GetInterCluster get nodes not in your cluster. Every round there is a given chance
|
||||||
// you will communicate with a random node that is not in your cluster.
|
// you will communicate with a random node that is not in your cluster.
|
||||||
func (i *ConnClusterImpl) GetInterCluster(global []string, selfId string) string {
|
func (i *ConnClusterImpl) GetInterCluster(global []string, selfId string) string {
|
||||||
// Doesn't matter if not in it. Get index of where the node 'should' be
|
// Doesn't matter if not in it. Get index of where the node 'should' be
|
||||||
@ -69,7 +66,6 @@ func (i *ConnClusterImpl) GetInterCluster(global []string, selfId string) string
|
|||||||
return global[neighbourIndex]
|
return global[neighbourIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewConnCluster: instantiate a new connection cluster of a given group size.
|
|
||||||
func NewConnCluster(clusterSize int) (ConnCluster, error) {
|
func NewConnCluster(clusterSize int) (ConnCluster, error) {
|
||||||
log2Cluster := math.Log2(float64(clusterSize))
|
log2Cluster := math.Log2(float64(clusterSize))
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
)
|
)
|
||||||
@ -18,7 +18,6 @@ type PeerConnection interface {
|
|||||||
GetClient() (*grpc.ClientConn, error)
|
GetClient() (*grpc.ClientConn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PeerConenctionFactory: create a new connection to a peer
|
|
||||||
type PeerConnectionFactory = func(clientConfig *tls.Config, server string) (PeerConnection, error)
|
type PeerConnectionFactory = func(clientConfig *tls.Config, server string) (PeerConnection, error)
|
||||||
|
|
||||||
// WgCtrlConnection implements PeerConnection.
|
// WgCtrlConnection implements PeerConnection.
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnectionManager defines an interface for maintaining peer connections
|
// ConnectionManager defines an interface for maintaining peer connections
|
||||||
@ -141,15 +141,9 @@ func (m *ConnectionManagerImpl) HasConnection(endPoint string) bool {
|
|||||||
// RemoveConnection removes the given connection if it exists
|
// RemoveConnection removes the given connection if it exists
|
||||||
func (m *ConnectionManagerImpl) RemoveConnection(endPoint string) error {
|
func (m *ConnectionManagerImpl) RemoveConnection(endPoint string) error {
|
||||||
m.conLoc.Lock()
|
m.conLoc.Lock()
|
||||||
connection, ok := m.clientConnections[endPoint]
|
err := m.clientConnections[endPoint].Close()
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if ok {
|
|
||||||
err = connection.Close()
|
|
||||||
delete(m.clientConnections, endPoint)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
delete(m.clientConnections, endPoint)
|
||||||
m.conLoc.Unlock()
|
m.conLoc.Unlock()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/rpc"
|
"github.com/tim-beatham/wgmesh/pkg/rpc"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
)
|
)
|
||||||
|
@ -9,20 +9,17 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Route: represents a route within the data store
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
// Destination the route is advertising
|
|
||||||
Destination string
|
Destination string
|
||||||
// Path to the destination
|
Path []string
|
||||||
Path []string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDestination implements mesh.Route.
|
// GetDestination implements mesh.Route.
|
||||||
@ -251,8 +248,7 @@ func (m *TwoPhaseStoreMeshManager) SaveChanges() {
|
|||||||
m.LastClock = clockValue
|
m.LastClock = clockValue
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateTimeStamp: update the timestamp of the given node, causes a configuration refresh if the node
|
// UpdateTimeStamp: update the timestamp of the given node
|
||||||
// is the leader causing all nodes to update their vector clocks
|
|
||||||
func (m *TwoPhaseStoreMeshManager) UpdateTimeStamp(nodeId string) error {
|
func (m *TwoPhaseStoreMeshManager) UpdateTimeStamp(nodeId string) error {
|
||||||
if !m.store.Contains(nodeId) {
|
if !m.store.Contains(nodeId) {
|
||||||
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
||||||
@ -268,7 +264,7 @@ func (m *TwoPhaseStoreMeshManager) UpdateTimeStamp(nodeId string) error {
|
|||||||
|
|
||||||
peerToUpdate := peers[0]
|
peerToUpdate := peers[0]
|
||||||
|
|
||||||
if uint64(time.Now().Unix())-m.store.Clock.GetTimestamp(peerToUpdate) > 3*uint64(m.DaemonConf.Heartbeat) {
|
if uint64(time.Now().Unix())-m.store.Clock.GetTimestamp(peerToUpdate) > 3*uint64(m.DaemonConf.KeepAliveTime) {
|
||||||
m.store.Mark(peerToUpdate)
|
m.store.Mark(peerToUpdate)
|
||||||
|
|
||||||
if len(peers) < 2 {
|
if len(peers) < 2 {
|
||||||
@ -316,8 +312,6 @@ func (m *TwoPhaseStoreMeshManager) AddRoutes(nodeId string, routes ...mesh.Route
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only add nodes on changes. Otherwise the node will advertise new
|
|
||||||
// information whenever they get new routes
|
|
||||||
if changes {
|
if changes {
|
||||||
m.store.Put(nodeId, node)
|
m.store.Put(nodeId, node)
|
||||||
}
|
}
|
||||||
@ -325,7 +319,7 @@ func (m *TwoPhaseStoreMeshManager) AddRoutes(nodeId string, routes ...mesh.Route
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveRoute: deletes the routes from the given node
|
// DeleteRoutes: deletes the routes from the node
|
||||||
func (m *TwoPhaseStoreMeshManager) RemoveRoutes(nodeId string, routes ...mesh.Route) error {
|
func (m *TwoPhaseStoreMeshManager) RemoveRoutes(nodeId string, routes ...mesh.Route) error {
|
||||||
if !m.store.Contains(nodeId) {
|
if !m.store.Contains(nodeId) {
|
||||||
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
||||||
@ -341,7 +335,6 @@ func (m *TwoPhaseStoreMeshManager) RemoveRoutes(nodeId string, routes ...mesh.Ro
|
|||||||
|
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
changes = true
|
changes = true
|
||||||
logging.Log.WriteInfof("deleting route: %s", route.GetDestination().String())
|
|
||||||
delete(node.Routes, route.GetDestination().String())
|
delete(node.Routes, route.GetDestination().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,12 +345,12 @@ func (m *TwoPhaseStoreMeshManager) RemoveRoutes(nodeId string, routes ...mesh.Ro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSyncer: returns the bi-directionally synchroniser to merge documents
|
// GetSyncer: returns the automerge syncer for sync
|
||||||
func (m *TwoPhaseStoreMeshManager) GetSyncer() mesh.MeshSyncer {
|
func (m *TwoPhaseStoreMeshManager) GetSyncer() mesh.MeshSyncer {
|
||||||
return NewTwoPhaseSyncer(m)
|
return NewTwoPhaseSyncer(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNode: get a particular not within the mesh network
|
// GetNode get a particular not within the mesh
|
||||||
func (m *TwoPhaseStoreMeshManager) GetNode(nodeId string) (mesh.MeshNode, error) {
|
func (m *TwoPhaseStoreMeshManager) GetNode(nodeId string) (mesh.MeshNode, error) {
|
||||||
if !m.store.Contains(nodeId) {
|
if !m.store.Contains(nodeId) {
|
||||||
return nil, fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
return nil, fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
||||||
@ -385,7 +378,7 @@ func (m *TwoPhaseStoreMeshManager) SetDescription(nodeId string, description str
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAlias: set the alias of the given node
|
// SetAlias: set the alias of the nodeId
|
||||||
func (m *TwoPhaseStoreMeshManager) SetAlias(nodeId string, alias string) error {
|
func (m *TwoPhaseStoreMeshManager) SetAlias(nodeId string, alias string) error {
|
||||||
if !m.store.Contains(nodeId) {
|
if !m.store.Contains(nodeId) {
|
||||||
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
||||||
@ -398,7 +391,7 @@ func (m *TwoPhaseStoreMeshManager) SetAlias(nodeId string, alias string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddService: adds a service to the given node
|
// AddService: adds the service to the given node
|
||||||
func (m *TwoPhaseStoreMeshManager) AddService(nodeId string, key string, value string) error {
|
func (m *TwoPhaseStoreMeshManager) AddService(nodeId string, key string, value string) error {
|
||||||
if !m.store.Contains(nodeId) {
|
if !m.store.Contains(nodeId) {
|
||||||
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
||||||
@ -410,7 +403,7 @@ func (m *TwoPhaseStoreMeshManager) AddService(nodeId string, key string, value s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveService: removes the service form a node, throws an error if the service does not exist
|
// RemoveService: removes the service form the node. throws an error if the service does not exist
|
||||||
func (m *TwoPhaseStoreMeshManager) RemoveService(nodeId string, key string) error {
|
func (m *TwoPhaseStoreMeshManager) RemoveService(nodeId string, key string) error {
|
||||||
if !m.store.Contains(nodeId) {
|
if !m.store.Contains(nodeId) {
|
||||||
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
||||||
@ -427,8 +420,7 @@ func (m *TwoPhaseStoreMeshManager) RemoveService(nodeId string, key string) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prune: prunes all nodes that have not updated their vector clock in a given amount
|
// Prune: prunes all nodes that have not updated their timestamp in
|
||||||
// of time
|
|
||||||
func (m *TwoPhaseStoreMeshManager) Prune() error {
|
func (m *TwoPhaseStoreMeshManager) Prune() error {
|
||||||
m.store.Prune()
|
m.store.Prune()
|
||||||
return nil
|
return nil
|
||||||
@ -457,7 +449,6 @@ func (m *TwoPhaseStoreMeshManager) GetPeers() []string {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRoutes: get all routes the target node is advertising
|
|
||||||
func (m *TwoPhaseStoreMeshManager) getRoutes(targetNode string) (map[string]Route, error) {
|
func (m *TwoPhaseStoreMeshManager) getRoutes(targetNode string) (map[string]Route, error) {
|
||||||
if !m.store.Contains(targetNode) {
|
if !m.store.Contains(targetNode) {
|
||||||
return nil, fmt.Errorf("getRoute: cannot get route %s does not exist", targetNode)
|
return nil, fmt.Errorf("getRoute: cannot get route %s does not exist", targetNode)
|
||||||
@ -467,8 +458,7 @@ func (m *TwoPhaseStoreMeshManager) getRoutes(targetNode string) (map[string]Rout
|
|||||||
return node.Routes, nil
|
return node.Routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRoutes: Get all unique routes the target node is advertising.
|
// GetRoutes(): Get all unique routes. Where the route with the least hop count is chosen
|
||||||
// on conflicts the route with the least hop count is chosen
|
|
||||||
func (m *TwoPhaseStoreMeshManager) GetRoutes(targetNode string) (map[string]mesh.Route, error) {
|
func (m *TwoPhaseStoreMeshManager) GetRoutes(targetNode string) (map[string]mesh.Route, error) {
|
||||||
node, err := m.GetNode(targetNode)
|
node, err := m.GetNode(targetNode)
|
||||||
|
|
||||||
@ -512,7 +502,7 @@ func (m *TwoPhaseStoreMeshManager) GetRoutes(targetNode string) (map[string]mesh
|
|||||||
return routes, nil
|
return routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveNode: remove the node from the mesh
|
// RemoveNode(): remove the node from the mesh
|
||||||
func (m *TwoPhaseStoreMeshManager) RemoveNode(nodeId string) error {
|
func (m *TwoPhaseStoreMeshManager) RemoveNode(nodeId string) error {
|
||||||
if !m.store.Contains(nodeId) {
|
if !m.store.Contains(nodeId) {
|
||||||
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
return fmt.Errorf("datastore: %s does not exist in the mesh", nodeId)
|
||||||
@ -522,8 +512,7 @@ func (m *TwoPhaseStoreMeshManager) RemoveNode(nodeId string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConfiguration gets the WireGuard configuration to use for this
|
// GetConfiguration implements mesh.MeshProvider.
|
||||||
// network
|
|
||||||
func (m *TwoPhaseStoreMeshManager) GetConfiguration() *conf.WgConfiguration {
|
func (m *TwoPhaseStoreMeshManager) GetConfiguration() *conf.WgConfiguration {
|
||||||
return m.Conf
|
return m.Conf
|
||||||
}
|
}
|
||||||
|
@ -6,9 +6,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ func setUpTests() *TestParams {
|
|||||||
advertiseRoutes := false
|
advertiseRoutes := false
|
||||||
advertiseDefaultRoute := false
|
advertiseDefaultRoute := false
|
||||||
role := conf.PEER_ROLE
|
role := conf.PEER_ROLE
|
||||||
discovery := conf.OUTGOING_IP_DISCOVERY
|
discovery := conf.DNS_IP_DISCOVERY
|
||||||
|
|
||||||
factory := &TwoPhaseMapFactory{
|
factory := &TwoPhaseMapFactory{
|
||||||
Config: &conf.DaemonConfiguration{
|
Config: &conf.DaemonConfiguration{
|
||||||
@ -31,11 +31,12 @@ func setUpTests() *TestParams {
|
|||||||
SkipCertVerification: true,
|
SkipCertVerification: true,
|
||||||
GrpcPort: 0,
|
GrpcPort: 0,
|
||||||
Timeout: 20,
|
Timeout: 20,
|
||||||
SyncInterval: 2,
|
Profile: false,
|
||||||
Heartbeat: 10,
|
SyncRate: 2,
|
||||||
|
KeepAliveTime: 10,
|
||||||
ClusterSize: 32,
|
ClusterSize: 32,
|
||||||
InterClusterChance: 0.15,
|
InterClusterChance: 0.15,
|
||||||
Branch: 3,
|
BranchRate: 3,
|
||||||
InfectionCount: 3,
|
InfectionCount: 3,
|
||||||
BaseConfiguration: conf.WgConfiguration{
|
BaseConfiguration: conf.WgConfiguration{
|
||||||
IPDiscovery: &discovery,
|
IPDiscovery: &discovery,
|
||||||
@ -214,6 +215,7 @@ func TestAddRoutesAddsARouteToTheGivenMesh(t *testing.T) {
|
|||||||
|
|
||||||
testParams.manager.AddRoutes(testParams.publicKey.String(), &mesh.RouteStub{
|
testParams.manager.AddRoutes(testParams.publicKey.String(), &mesh.RouteStub{
|
||||||
Destination: destination,
|
Destination: destination,
|
||||||
|
HopCount: 0,
|
||||||
Path: make([]string, 0),
|
Path: make([]string, 0),
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -236,6 +238,7 @@ func TestRemoveRoutesWithdrawsRoutesFromTheMesh(t *testing.T) {
|
|||||||
_, destination, _ := net.ParseCIDR("0353:1da7:7f33:acc0:7a3f:6e55:912b:bc1f/64")
|
_, destination, _ := net.ParseCIDR("0353:1da7:7f33:acc0:7a3f:6e55:912b:bc1f/64")
|
||||||
route := &mesh.RouteStub{
|
route := &mesh.RouteStub{
|
||||||
Destination: destination,
|
Destination: destination,
|
||||||
|
HopCount: 0,
|
||||||
Path: make([]string, 0),
|
Path: make([]string, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,18 +4,15 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TwoPhaseMapFactory: instantiate a new twophasemap
|
|
||||||
// datastore
|
|
||||||
type TwoPhaseMapFactory struct {
|
type TwoPhaseMapFactory struct {
|
||||||
Config *conf.DaemonConfiguration
|
Config *conf.DaemonConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMesh: create a new mesh network
|
|
||||||
func (f *TwoPhaseMapFactory) CreateMesh(params *mesh.MeshProviderFactoryParams) (mesh.MeshProvider, error) {
|
func (f *TwoPhaseMapFactory) CreateMesh(params *mesh.MeshProviderFactoryParams) (mesh.MeshProvider, error) {
|
||||||
return &TwoPhaseStoreMeshManager{
|
return &TwoPhaseStoreMeshManager{
|
||||||
MeshId: params.MeshId,
|
MeshId: params.MeshId,
|
||||||
@ -27,16 +24,14 @@ func (f *TwoPhaseMapFactory) CreateMesh(params *mesh.MeshProviderFactoryParams)
|
|||||||
h := fnv.New64a()
|
h := fnv.New64a()
|
||||||
h.Write([]byte(s))
|
h.Write([]byte(s))
|
||||||
return h.Sum64()
|
return h.Sum64()
|
||||||
}, uint64(3*f.Config.Heartbeat)),
|
}, uint64(3*f.Config.KeepAliveTime)),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeshNodeFactory: create a new node in the mesh network
|
|
||||||
type MeshNodeFactory struct {
|
type MeshNodeFactory struct {
|
||||||
Config conf.DaemonConfiguration
|
Config conf.DaemonConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build: build a new mesh network
|
|
||||||
func (f *MeshNodeFactory) Build(params *mesh.MeshNodeFactoryParams) mesh.MeshNode {
|
func (f *MeshNodeFactory) Build(params *mesh.MeshNodeFactoryParams) mesh.MeshNode {
|
||||||
hostName := f.getAddress(params)
|
hostName := f.getAddress(params)
|
||||||
|
|
||||||
@ -71,7 +66,7 @@ func (f *MeshNodeFactory) getAddress(params *mesh.MeshNodeFactoryParams) string
|
|||||||
} else {
|
} else {
|
||||||
ipFunc := lib.GetPublicIP
|
ipFunc := lib.GetPublicIP
|
||||||
|
|
||||||
if *params.MeshConfig.IPDiscovery == conf.OUTGOING_IP_DISCOVERY {
|
if *params.MeshConfig.IPDiscovery == conf.DNS_IP_DISCOVERY {
|
||||||
ipFunc = lib.GetOutboundIP
|
ipFunc = lib.GetOutboundIP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bucket: bucket represents a value in the grow only map
|
|
||||||
type Bucket[D any] struct {
|
type Bucket[D any] struct {
|
||||||
Vector uint64
|
Vector uint64
|
||||||
Contents D
|
Contents D
|
||||||
@ -20,7 +19,6 @@ type GMap[K cmp.Ordered, D any] struct {
|
|||||||
clock *VectorClock[K]
|
clock *VectorClock[K]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put: put a new entry in the grow-only-map
|
|
||||||
func (g *GMap[K, D]) Put(key K, value D) {
|
func (g *GMap[K, D]) Put(key K, value D) {
|
||||||
g.lock.Lock()
|
g.lock.Lock()
|
||||||
|
|
||||||
@ -34,8 +32,6 @@ func (g *GMap[K, D]) Put(key K, value D) {
|
|||||||
g.lock.Unlock()
|
g.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contains: returns whether or not the key is contained
|
|
||||||
// in the g-map
|
|
||||||
func (g *GMap[K, D]) Contains(key K) bool {
|
func (g *GMap[K, D]) Contains(key K) bool {
|
||||||
return g.contains(g.clock.hashFunc(key))
|
return g.contains(g.clock.hashFunc(key))
|
||||||
}
|
}
|
||||||
@ -68,7 +64,6 @@ func (g *GMap[K, D]) get(key uint64) Bucket[D] {
|
|||||||
return bucket
|
return bucket
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get: get the value associated with the given key
|
|
||||||
func (g *GMap[K, D]) Get(key K) D {
|
func (g *GMap[K, D]) Get(key K) D {
|
||||||
if !g.Contains(key) {
|
if !g.Contains(key) {
|
||||||
var def D
|
var def D
|
||||||
@ -78,8 +73,6 @@ func (g *GMap[K, D]) Get(key K) D {
|
|||||||
return g.get(g.clock.hashFunc(key)).Contents
|
return g.get(g.clock.hashFunc(key)).Contents
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark: marks the node, this means the status of the node
|
|
||||||
// is an undefined state
|
|
||||||
func (g *GMap[K, D]) Mark(key K) {
|
func (g *GMap[K, D]) Mark(key K) {
|
||||||
if !g.Contains(key) {
|
if !g.Contains(key) {
|
||||||
return
|
return
|
||||||
@ -92,7 +85,7 @@ func (g *GMap[K, D]) Mark(key K) {
|
|||||||
g.lock.Unlock()
|
g.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsMarked: returns true if the node is marked (in an undefined state)
|
// IsMarked: returns true if the node is marked
|
||||||
func (g *GMap[K, D]) IsMarked(key K) bool {
|
func (g *GMap[K, D]) IsMarked(key K) bool {
|
||||||
marked := false
|
marked := false
|
||||||
|
|
||||||
@ -108,7 +101,6 @@ func (g *GMap[K, D]) IsMarked(key K) bool {
|
|||||||
return marked
|
return marked
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keys: return all the keys in the grow-only map
|
|
||||||
func (g *GMap[K, D]) Keys() []uint64 {
|
func (g *GMap[K, D]) Keys() []uint64 {
|
||||||
g.lock.RLock()
|
g.lock.RLock()
|
||||||
|
|
||||||
@ -124,7 +116,6 @@ func (g *GMap[K, D]) Keys() []uint64 {
|
|||||||
return contents
|
return contents
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save: saves the grow only map
|
|
||||||
func (g *GMap[K, D]) Save() map[uint64]Bucket[D] {
|
func (g *GMap[K, D]) Save() map[uint64]Bucket[D] {
|
||||||
buckets := make(map[uint64]Bucket[D])
|
buckets := make(map[uint64]Bucket[D])
|
||||||
g.lock.RLock()
|
g.lock.RLock()
|
||||||
@ -137,7 +128,6 @@ func (g *GMap[K, D]) Save() map[uint64]Bucket[D] {
|
|||||||
return buckets
|
return buckets
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveWithKeys: get all the values corresponding with the provided keys
|
|
||||||
func (g *GMap[K, D]) SaveWithKeys(keys []uint64) map[uint64]Bucket[D] {
|
func (g *GMap[K, D]) SaveWithKeys(keys []uint64) map[uint64]Bucket[D] {
|
||||||
buckets := make(map[uint64]Bucket[D])
|
buckets := make(map[uint64]Bucket[D])
|
||||||
g.lock.RLock()
|
g.lock.RLock()
|
||||||
@ -150,7 +140,6 @@ func (g *GMap[K, D]) SaveWithKeys(keys []uint64) map[uint64]Bucket[D] {
|
|||||||
return buckets
|
return buckets
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClock: get all the vector clocks in the g_map
|
|
||||||
func (g *GMap[K, D]) GetClock() map[uint64]uint64 {
|
func (g *GMap[K, D]) GetClock() map[uint64]uint64 {
|
||||||
clock := make(map[uint64]uint64)
|
clock := make(map[uint64]uint64)
|
||||||
g.lock.RLock()
|
g.lock.RLock()
|
||||||
@ -163,7 +152,6 @@ func (g *GMap[K, D]) GetClock() map[uint64]uint64 {
|
|||||||
return clock
|
return clock
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetHash: get the hash of the g_map representing its state
|
|
||||||
func (g *GMap[K, D]) GetHash() uint64 {
|
func (g *GMap[K, D]) GetHash() uint64 {
|
||||||
hash := uint64(0)
|
hash := uint64(0)
|
||||||
|
|
||||||
@ -177,7 +165,6 @@ func (g *GMap[K, D]) GetHash() uint64 {
|
|||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prune: prune all stale entries
|
|
||||||
func (g *GMap[K, D]) Prune() {
|
func (g *GMap[K, D]) Prune() {
|
||||||
stale := g.clock.getStale()
|
stale := g.clock.getStale()
|
||||||
g.lock.Lock()
|
g.lock.Lock()
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewGmap() *GMap[string, bool] {
|
func NewGmap() *GMap[string, bool] {
|
||||||
|
@ -3,10 +3,9 @@ package crdt
|
|||||||
import (
|
import (
|
||||||
"cmp"
|
"cmp"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TwoPhaseMap: comprises of two grow-only maps
|
|
||||||
type TwoPhaseMap[K cmp.Ordered, D any] struct {
|
type TwoPhaseMap[K cmp.Ordered, D any] struct {
|
||||||
addMap *GMap[K, D]
|
addMap *GMap[K, D]
|
||||||
removeMap *GMap[K, bool]
|
removeMap *GMap[K, bool]
|
||||||
@ -24,7 +23,7 @@ func (m *TwoPhaseMap[K, D]) Contains(key K) bool {
|
|||||||
return m.contains(m.Clock.hashFunc(key))
|
return m.contains(m.Clock.hashFunc(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
// contains: checks whether the key exists in the map
|
// Contains checks whether the value exists in the map
|
||||||
func (m *TwoPhaseMap[K, D]) contains(key uint64) bool {
|
func (m *TwoPhaseMap[K, D]) contains(key uint64) bool {
|
||||||
if !m.addMap.contains(key) {
|
if !m.addMap.contains(key) {
|
||||||
return false
|
return false
|
||||||
@ -41,7 +40,6 @@ func (m *TwoPhaseMap[K, D]) contains(key uint64) bool {
|
|||||||
return addValue.Vector >= removeValue.Vector
|
return addValue.Vector >= removeValue.Vector
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get: get the value corresponding with the given key
|
|
||||||
func (m *TwoPhaseMap[K, D]) Get(key K) D {
|
func (m *TwoPhaseMap[K, D]) Get(key K) D {
|
||||||
var result D
|
var result D
|
||||||
|
|
||||||
@ -62,19 +60,18 @@ func (m *TwoPhaseMap[K, D]) get(key uint64) D {
|
|||||||
return m.addMap.get(key).Contents
|
return m.addMap.get(key).Contents
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put: places the key K in the map with the associated data D
|
// Put places the key K in the map
|
||||||
func (m *TwoPhaseMap[K, D]) Put(key K, data D) {
|
func (m *TwoPhaseMap[K, D]) Put(key K, data D) {
|
||||||
msgSequence := m.Clock.IncrementClock()
|
msgSequence := m.Clock.IncrementClock()
|
||||||
m.Clock.Put(key, msgSequence)
|
m.Clock.Put(key, msgSequence)
|
||||||
m.addMap.Put(key, data)
|
m.addMap.Put(key, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark: marks the status of the node as undetermiend
|
|
||||||
func (m *TwoPhaseMap[K, D]) Mark(key K) {
|
func (m *TwoPhaseMap[K, D]) Mark(key K) {
|
||||||
m.addMap.Mark(key)
|
m.addMap.Mark(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove: removes the value from the map
|
// Remove removes the value from the map
|
||||||
func (m *TwoPhaseMap[K, D]) Remove(key K) {
|
func (m *TwoPhaseMap[K, D]) Remove(key K) {
|
||||||
m.removeMap.Put(key, true)
|
m.removeMap.Put(key, true)
|
||||||
}
|
}
|
||||||
@ -95,7 +92,6 @@ func (m *TwoPhaseMap[K, D]) keys() []uint64 {
|
|||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
// AsList: convert the map to a list
|
|
||||||
func (m *TwoPhaseMap[K, D]) AsList() []D {
|
func (m *TwoPhaseMap[K, D]) AsList() []D {
|
||||||
theList := make([]D, 0)
|
theList := make([]D, 0)
|
||||||
|
|
||||||
@ -108,8 +104,6 @@ func (m *TwoPhaseMap[K, D]) AsList() []D {
|
|||||||
return theList
|
return theList
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot: convert the map into an immutable snapshot.
|
|
||||||
// contains the contents of the add and remove map
|
|
||||||
func (m *TwoPhaseMap[K, D]) Snapshot() *TwoPhaseMapSnapshot[K, D] {
|
func (m *TwoPhaseMap[K, D]) Snapshot() *TwoPhaseMapSnapshot[K, D] {
|
||||||
return &TwoPhaseMapSnapshot[K, D]{
|
return &TwoPhaseMapSnapshot[K, D]{
|
||||||
Add: m.addMap.Save(),
|
Add: m.addMap.Save(),
|
||||||
@ -117,8 +111,6 @@ func (m *TwoPhaseMap[K, D]) Snapshot() *TwoPhaseMapSnapshot[K, D] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnapshotFromState: create a snapshot of the intersection of values provided
|
|
||||||
// in the given state
|
|
||||||
func (m *TwoPhaseMap[K, D]) SnapShotFromState(state *TwoPhaseMapState[K]) *TwoPhaseMapSnapshot[K, D] {
|
func (m *TwoPhaseMap[K, D]) SnapShotFromState(state *TwoPhaseMapState[K]) *TwoPhaseMapSnapshot[K, D] {
|
||||||
addKeys := lib.MapKeys(state.AddContents)
|
addKeys := lib.MapKeys(state.AddContents)
|
||||||
removeKeys := lib.MapKeys(state.RemoveContents)
|
removeKeys := lib.MapKeys(state.RemoveContents)
|
||||||
@ -129,18 +121,12 @@ func (m *TwoPhaseMap[K, D]) SnapShotFromState(state *TwoPhaseMapState[K]) *TwoPh
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TwoPhaseMapState: encapsulates the state of the map
|
|
||||||
// without specifying the data that is stored
|
|
||||||
type TwoPhaseMapState[K cmp.Ordered] struct {
|
type TwoPhaseMapState[K cmp.Ordered] struct {
|
||||||
// Vectors: the vector ID of each process
|
|
||||||
Vectors map[uint64]uint64
|
Vectors map[uint64]uint64
|
||||||
// AddContents: the contents of the add map
|
|
||||||
AddContents map[uint64]uint64
|
AddContents map[uint64]uint64
|
||||||
// RemoveContents: the contents of the remove map
|
|
||||||
RemoveContents map[uint64]uint64
|
RemoveContents map[uint64]uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsMarked: returns true if the given value is marked in an undetermined state
|
|
||||||
func (m *TwoPhaseMap[K, D]) IsMarked(key K) bool {
|
func (m *TwoPhaseMap[K, D]) IsMarked(key K) bool {
|
||||||
return m.addMap.IsMarked(key)
|
return m.addMap.IsMarked(key)
|
||||||
}
|
}
|
||||||
@ -165,8 +151,6 @@ func (m *TwoPhaseMap[K, D]) GenerateMessage() *TwoPhaseMapState[K] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Difference: compute the set difference between the two states.
|
|
||||||
// highestStale represents the highest vector clock that has been marked as stale
|
|
||||||
func (m *TwoPhaseMapState[K]) Difference(highestStale uint64, state *TwoPhaseMapState[K]) *TwoPhaseMapState[K] {
|
func (m *TwoPhaseMapState[K]) Difference(highestStale uint64, state *TwoPhaseMapState[K]) *TwoPhaseMapState[K] {
|
||||||
mapState := &TwoPhaseMapState[K]{
|
mapState := &TwoPhaseMapState[K]{
|
||||||
AddContents: make(map[uint64]uint64),
|
AddContents: make(map[uint64]uint64),
|
||||||
@ -192,7 +176,6 @@ func (m *TwoPhaseMapState[K]) Difference(highestStale uint64, state *TwoPhaseMap
|
|||||||
return mapState
|
return mapState
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge: merge a snapshot into the map
|
|
||||||
func (m *TwoPhaseMap[K, D]) Merge(snapshot TwoPhaseMapSnapshot[K, D]) {
|
func (m *TwoPhaseMap[K, D]) Merge(snapshot TwoPhaseMapSnapshot[K, D]) {
|
||||||
for key, value := range snapshot.Add {
|
for key, value := range snapshot.Add {
|
||||||
// Gravestone is local only to that node.
|
// Gravestone is local only to that node.
|
||||||
@ -207,7 +190,6 @@ func (m *TwoPhaseMap[K, D]) Merge(snapshot TwoPhaseMapSnapshot[K, D]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prune: garbage collect all stale entries in the map
|
|
||||||
func (m *TwoPhaseMap[K, D]) Prune() {
|
func (m *TwoPhaseMap[K, D]) Prune() {
|
||||||
m.addMap.Prune()
|
m.addMap.Prune()
|
||||||
m.removeMap.Prune()
|
m.removeMap.Prune()
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
|
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SyncState int
|
type SyncState int
|
||||||
|
@ -5,12 +5,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VectorBucket: represents a vector clock in the bucket
|
|
||||||
// recording both the time changes were last seen
|
|
||||||
// and when the lastUpdate epoch was recorded
|
|
||||||
type VectorBucket struct {
|
type VectorBucket struct {
|
||||||
// clock current value of the node's clock
|
// clock current value of the node's clock
|
||||||
clock uint64
|
clock uint64
|
||||||
@ -18,9 +15,8 @@ type VectorBucket struct {
|
|||||||
lastUpdate uint64
|
lastUpdate uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// VectorClock: defines an abstract data type
|
// Vector clock defines an abstract data type
|
||||||
// for a vector clock implementation. Including a mechanism to
|
// for a vector clock implementation
|
||||||
// garbage collect stale entries
|
|
||||||
type VectorClock[K cmp.Ordered] struct {
|
type VectorClock[K cmp.Ordered] struct {
|
||||||
vectors map[uint64]*VectorBucket
|
vectors map[uint64]*VectorBucket
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
@ -66,7 +62,6 @@ func (m *VectorClock[K]) GetHash() uint64 {
|
|||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge: merge two clocks together
|
|
||||||
func (m *VectorClock[K]) Merge(vectors map[uint64]uint64) {
|
func (m *VectorClock[K]) Merge(vectors map[uint64]uint64) {
|
||||||
for key, value := range vectors {
|
for key, value := range vectors {
|
||||||
m.put(key, value)
|
m.put(key, value)
|
||||||
@ -102,7 +97,6 @@ func (m *VectorClock[K]) GetStaleCount() uint64 {
|
|||||||
return staleCount
|
return staleCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prune: prunes all stale entries in the vector clock
|
|
||||||
func (m *VectorClock[K]) Prune() {
|
func (m *VectorClock[K]) Prune() {
|
||||||
stale := m.getStale()
|
stale := m.getStale()
|
||||||
|
|
||||||
@ -115,8 +109,6 @@ func (m *VectorClock[K]) Prune() {
|
|||||||
m.lock.Unlock()
|
m.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTimeStamp: get the last time the node was updated in UNIX
|
|
||||||
// epoch time
|
|
||||||
func (m *VectorClock[K]) GetTimestamp(processId K) uint64 {
|
func (m *VectorClock[K]) GetTimestamp(processId K) uint64 {
|
||||||
m.lock.RLock()
|
m.lock.RLock()
|
||||||
|
|
||||||
@ -126,8 +118,6 @@ func (m *VectorClock[K]) GetTimestamp(processId K) uint64 {
|
|||||||
return lastUpdate
|
return lastUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put: places the key with vector clock in the clock of the given
|
|
||||||
// process
|
|
||||||
func (m *VectorClock[K]) Put(key K, value uint64) {
|
func (m *VectorClock[K]) Put(key K, value uint64) {
|
||||||
m.put(m.hashFunc(key), value)
|
m.put(m.hashFunc(key), value)
|
||||||
}
|
}
|
||||||
@ -143,8 +133,7 @@ func (m *VectorClock[K]) put(key uint64, value uint64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that entries that were garbage collected don't get
|
// Make sure that entries that were garbage collected don't get
|
||||||
// highestStale represents the highest vector clock that has been
|
// addded back
|
||||||
// invalidated
|
|
||||||
if value > clockValue && value > m.highestStale {
|
if value > clockValue && value > m.highestStale {
|
||||||
newBucket := VectorBucket{
|
newBucket := VectorBucket{
|
||||||
clock: value,
|
clock: value,
|
||||||
@ -156,7 +145,6 @@ func (m *VectorClock[K]) put(key uint64, value uint64) {
|
|||||||
m.lock.Unlock()
|
m.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClock: serialize the vector clock into an immutable map
|
|
||||||
func (m *VectorClock[K]) GetClock() map[uint64]uint64 {
|
func (m *VectorClock[K]) GetClock() map[uint64]uint64 {
|
||||||
clock := make(map[uint64]uint64)
|
clock := make(map[uint64]uint64)
|
||||||
|
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
package ctrlserver
|
package ctrlserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conn"
|
"github.com/tim-beatham/wgmesh/pkg/conn"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/crdt"
|
"github.com/tim-beatham/wgmesh/pkg/crdt"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ip"
|
"github.com/tim-beatham/wgmesh/pkg/ip"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/query"
|
"github.com/tim-beatham/wgmesh/pkg/query"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/rpc"
|
"github.com/tim-beatham/wgmesh/pkg/rpc"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/sync"
|
"github.com/tim-beatham/wgmesh/pkg/wg"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/wg"
|
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewCtrlServerParams are the params required to create a new ctrl server
|
// NewCtrlServerParams are the params requried to create a new ctrl server
|
||||||
type NewCtrlServerParams struct {
|
type NewCtrlServerParams struct {
|
||||||
Conf *conf.DaemonConfiguration
|
Conf *conf.DaemonConfiguration
|
||||||
Client *wgctrl.Client
|
Client *wgctrl.Client
|
||||||
CtrlProvider rpc.MeshCtrlServerServer
|
CtrlProvider rpc.MeshCtrlServerServer
|
||||||
SyncProvider rpc.SyncServiceServer
|
SyncProvider rpc.SyncServiceServer
|
||||||
Querier query.Querier
|
Querier query.Querier
|
||||||
|
OnDelete func(mesh.MeshProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new instance of the MeshCtrlServer or error if the
|
// Create a new instance of the MeshCtrlServer or error if the
|
||||||
@ -34,15 +34,11 @@ func NewCtrlServer(params *NewCtrlServerParams) (*MeshCtrlServer, error) {
|
|||||||
nodeFactory := &crdt.MeshNodeFactory{
|
nodeFactory := &crdt.MeshNodeFactory{
|
||||||
Config: *params.Conf,
|
Config: *params.Conf,
|
||||||
}
|
}
|
||||||
idGenerator := &lib.ShortIDGenerator{}
|
idGenerator := &lib.IDNameGenerator{}
|
||||||
ipAllocator := &ip.ULABuilder{}
|
ipAllocator := &ip.ULABuilder{}
|
||||||
interfaceManipulator := wg.NewWgInterfaceManipulator(params.Client)
|
interfaceManipulator := wg.NewWgInterfaceManipulator(params.Client)
|
||||||
|
|
||||||
ctrlServer.timers = make([]*lib.Timer, 0)
|
configApplyer := mesh.NewWgMeshConfigApplyer()
|
||||||
|
|
||||||
configApplier := mesh.NewWgMeshConfigApplier()
|
|
||||||
|
|
||||||
var syncer sync.Syncer
|
|
||||||
|
|
||||||
meshManagerParams := &mesh.NewMeshManagerParams{
|
meshManagerParams := &mesh.NewMeshManagerParams{
|
||||||
Conf: *params.Conf,
|
Conf: *params.Conf,
|
||||||
@ -52,18 +48,12 @@ func NewCtrlServer(params *NewCtrlServerParams) (*MeshCtrlServer, error) {
|
|||||||
IdGenerator: idGenerator,
|
IdGenerator: idGenerator,
|
||||||
IPAllocator: ipAllocator,
|
IPAllocator: ipAllocator,
|
||||||
InterfaceManipulator: interfaceManipulator,
|
InterfaceManipulator: interfaceManipulator,
|
||||||
ConfigApplier: configApplier,
|
ConfigApplyer: configApplyer,
|
||||||
OnDelete: func(mesh mesh.MeshProvider) {
|
OnDelete: params.OnDelete,
|
||||||
_, err := syncer.Sync(mesh)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logging.Log.WriteErrorf(err.Error())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrlServer.MeshManager = mesh.NewMeshManager(meshManagerParams)
|
ctrlServer.MeshManager = mesh.NewMeshManager(meshManagerParams)
|
||||||
configApplier.SetMeshManager(ctrlServer.MeshManager)
|
configApplyer.SetMeshManager(ctrlServer.MeshManager)
|
||||||
|
|
||||||
ctrlServer.Conf = params.Conf
|
ctrlServer.Conf = params.Conf
|
||||||
connManagerParams := conn.NewConnectionManagerParams{
|
connManagerParams := conn.NewConnectionManagerParams{
|
||||||
@ -93,40 +83,13 @@ func NewCtrlServer(params *NewCtrlServerParams) (*MeshCtrlServer, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
syncer = sync.NewSyncer(&sync.NewSyncerParams{
|
|
||||||
MeshManager: ctrlServer.MeshManager,
|
|
||||||
ConnectionManager: ctrlServer.ConnectionManager,
|
|
||||||
Configuration: params.Conf,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Check any syncs every 1 second
|
|
||||||
syncTimer := lib.NewTimer(func() error {
|
|
||||||
err = syncer.SyncMeshes()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logging.Log.WriteErrorf(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}, 1)
|
|
||||||
|
|
||||||
heartbeatTimer := lib.NewTimer(func() error {
|
|
||||||
logging.Log.WriteInfof("checking heartbeat")
|
|
||||||
return ctrlServer.MeshManager.UpdateTimeStamp()
|
|
||||||
}, params.Conf.Heartbeat)
|
|
||||||
|
|
||||||
ctrlServer.timers = append(ctrlServer.timers, syncTimer, heartbeatTimer)
|
|
||||||
|
|
||||||
ctrlServer.Querier = query.NewJmesQuerier(ctrlServer.MeshManager)
|
ctrlServer.Querier = query.NewJmesQuerier(ctrlServer.MeshManager)
|
||||||
ctrlServer.ConnectionServer = connServer
|
ctrlServer.ConnectionServer = connServer
|
||||||
|
|
||||||
for _, timer := range ctrlServer.timers {
|
|
||||||
go timer.Run()
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctrlServer, nil
|
return ctrlServer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *MeshCtrlServer) GetConfiguration() *conf.DaemonConfiguration {
|
func (s *MeshCtrlServer) GetConfiguration() *conf.DaemonConfiguration {
|
||||||
return s.Conf
|
return s.Conf
|
||||||
}
|
}
|
||||||
@ -161,13 +124,5 @@ func (s *MeshCtrlServer) Close() error {
|
|||||||
logging.Log.WriteErrorf(err.Error())
|
logging.Log.WriteErrorf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, timer := range s.timers {
|
|
||||||
err := timer.Stop()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logging.Log.WriteErrorf(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -4,23 +4,21 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conn"
|
"github.com/tim-beatham/wgmesh/pkg/conn"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/query"
|
"github.com/tim-beatham/wgmesh/pkg/query"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MeshRoute: represents a route in the mesh that is
|
|
||||||
// available to client applications
|
|
||||||
type MeshRoute struct {
|
type MeshRoute struct {
|
||||||
Destination string
|
Destination string
|
||||||
Path []string
|
Path []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// WireGuardStats: Represents the WireGuard configuration attached to the node
|
// Represents the WireGuard configuration attached to the node
|
||||||
type WireGuardStats struct {
|
type WireGuardStats struct {
|
||||||
AllowedIPs []string
|
AllowedIPs []string
|
||||||
TransmitBytes int64
|
TransmitBytes int64
|
||||||
@ -28,8 +26,7 @@ type WireGuardStats struct {
|
|||||||
PersistentKeepAliveInterval time.Duration
|
PersistentKeepAliveInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeshNode: represents a node in the WireGuard mesh that can be
|
// Represents a WireGuard MeshNode
|
||||||
// sent to ip chandlers
|
|
||||||
type MeshNode struct {
|
type MeshNode struct {
|
||||||
HostEndpoint string
|
HostEndpoint string
|
||||||
WgEndpoint string
|
WgEndpoint string
|
||||||
@ -43,13 +40,12 @@ type MeshNode struct {
|
|||||||
Stats WireGuardStats
|
Stats WireGuardStats
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mesh: Represents a WireGuard Mesh network that can be sent
|
// Represents a WireGuard Mesh
|
||||||
// along ipc to client frameworks
|
|
||||||
type Mesh struct {
|
type Mesh struct {
|
||||||
|
SharedKey *wgtypes.Key
|
||||||
Nodes map[string]MeshNode
|
Nodes map[string]MeshNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// CtrlServer: Encapsulates th ctrlserver
|
|
||||||
type CtrlServer interface {
|
type CtrlServer interface {
|
||||||
GetConfiguration() *conf.DaemonConfiguration
|
GetConfiguration() *conf.DaemonConfiguration
|
||||||
GetClient() *wgctrl.Client
|
GetClient() *wgctrl.Client
|
||||||
@ -59,7 +55,7 @@ type CtrlServer interface {
|
|||||||
GetConnectionManager() conn.ConnectionManager
|
GetConnectionManager() conn.ConnectionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeshCtrlServer: Represents a ctrlserver to be used in WireGuard
|
// Represents a ctrlserver to be used in WireGuard
|
||||||
type MeshCtrlServer struct {
|
type MeshCtrlServer struct {
|
||||||
Client *wgctrl.Client
|
Client *wgctrl.Client
|
||||||
MeshManager mesh.MeshManager
|
MeshManager mesh.MeshManager
|
||||||
@ -67,7 +63,6 @@ type MeshCtrlServer struct {
|
|||||||
ConnectionServer *conn.ConnectionServer
|
ConnectionServer *conn.ConnectionServer
|
||||||
Conf *conf.DaemonConfiguration
|
Conf *conf.DaemonConfiguration
|
||||||
Querier query.Querier
|
Querier query.Querier
|
||||||
timers []*lib.Timer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCtrlNode create an instance of a ctrl node to send over an
|
// NewCtrlNode create an instance of a ctrl node to send over an
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package ctrlserver
|
package ctrlserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conn"
|
"github.com/tim-beatham/wgmesh/pkg/conn"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/query"
|
"github.com/tim-beatham/wgmesh/pkg/query"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,22 +1,24 @@
|
|||||||
// smegdns: example of how to implement dns in the mesh
|
|
||||||
package smegdns
|
package smegdns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"net/rpc"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ipc"
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/query"
|
"github.com/tim-beatham/wgmesh/pkg/query"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
||||||
|
|
||||||
const MeshRegularExpression = `(?P<meshId>.+)\.(?P<alias>.+)\.smeg\.`
|
const MeshRegularExpression = `(?P<meshId>.+)\.(?P<alias>.+)\.smeg\.`
|
||||||
|
|
||||||
type DNSHandler struct {
|
type DNSHandler struct {
|
||||||
client *ipc.SmegmeshIpc
|
client *rpc.Client
|
||||||
server *dns.Server
|
server *dns.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +27,7 @@ type DNSHandler struct {
|
|||||||
func (d *DNSHandler) queryMesh(meshId, alias string) net.IP {
|
func (d *DNSHandler) queryMesh(meshId, alias string) net.IP {
|
||||||
var reply string
|
var reply string
|
||||||
|
|
||||||
err := d.client.Query(ipc.QueryMesh{
|
err := d.client.Call("IpcHandler.Query", &ipc.QueryMesh{
|
||||||
MeshId: meshId,
|
MeshId: meshId,
|
||||||
Query: fmt.Sprintf("[?alias == '%s'] | [0]", alias),
|
Query: fmt.Sprintf("[?alias == '%s'] | [0]", alias),
|
||||||
}, &reply)
|
}, &reply)
|
||||||
@ -46,7 +48,6 @@ func (d *DNSHandler) queryMesh(meshId, alias string) net.IP {
|
|||||||
return ip
|
return ip
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleQuery: handles a DNS query
|
|
||||||
func (d *DNSHandler) handleQuery(m *dns.Msg) {
|
func (d *DNSHandler) handleQuery(m *dns.Msg) {
|
||||||
for _, q := range m.Question {
|
for _, q := range m.Question {
|
||||||
switch q.Qtype {
|
switch q.Qtype {
|
||||||
@ -74,7 +75,6 @@ func (d *DNSHandler) handleQuery(m *dns.Msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleDNS query: handle a DNS request
|
|
||||||
func (h *DNSHandler) handleDnsRequest(w dns.ResponseWriter, r *dns.Msg) {
|
func (h *DNSHandler) handleDnsRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||||
msg := new(dns.Msg)
|
msg := new(dns.Msg)
|
||||||
msg.SetReply(r)
|
msg.SetReply(r)
|
||||||
@ -97,7 +97,7 @@ func (h *DNSHandler) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewDns(udpPort int) (*DNSHandler, error) {
|
func NewDns(udpPort int) (*DNSHandler, error) {
|
||||||
client, err := ipc.NewClientIpc()
|
client, err := rpc.DialHTTP("unix", SockAddr)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GraphType string
|
type GraphType string
|
||||||
@ -29,7 +29,6 @@ type Graph interface {
|
|||||||
GetType() GraphType
|
GetType() GraphType
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cluster: represents a subgraph in the graphs
|
|
||||||
type Cluster struct {
|
type Cluster struct {
|
||||||
Type GraphType
|
Type GraphType
|
||||||
Name string
|
Name string
|
||||||
@ -38,7 +37,6 @@ type Cluster struct {
|
|||||||
edges map[string]Edge
|
edges map[string]Edge
|
||||||
}
|
}
|
||||||
|
|
||||||
// RootGraph: Represents the top level graph
|
|
||||||
type RootGraph struct {
|
type RootGraph struct {
|
||||||
Type GraphType
|
Type GraphType
|
||||||
Label string
|
Label string
|
||||||
@ -47,7 +45,6 @@ type RootGraph struct {
|
|||||||
edges map[string]Edge
|
edges map[string]Edge
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node: represents a graphviz not
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
Name string
|
Name string
|
||||||
Label string
|
Label string
|
||||||
@ -55,12 +52,10 @@ type Node struct {
|
|||||||
Size int
|
Size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edge: represents an edge between adjacent nodes
|
|
||||||
type Edge interface {
|
type Edge interface {
|
||||||
Dottable
|
Dottable
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirectEdge: contains a directed edge between any two nodes
|
|
||||||
type DirectedEdge struct {
|
type DirectedEdge struct {
|
||||||
Name string
|
Name string
|
||||||
Label string
|
Label string
|
||||||
@ -68,8 +63,6 @@ type DirectedEdge struct {
|
|||||||
To string
|
To string
|
||||||
}
|
}
|
||||||
|
|
||||||
// UndirectedEdge: contains an undirected edge between any two
|
|
||||||
// nodes
|
|
||||||
type UndirectedEdge struct {
|
type UndirectedEdge struct {
|
||||||
Name string
|
Name string
|
||||||
Label string
|
Label string
|
||||||
@ -82,7 +75,11 @@ type Dottable interface {
|
|||||||
GetDOT() (string, error)
|
GetDOT() (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutNode: puts a node in the root graph
|
func NewGraph(label string, graphType GraphType) *RootGraph {
|
||||||
|
return &RootGraph{Type: graphType, Label: label, clusters: map[string]*Cluster{}, nodes: make(map[string]*Node), edges: make(map[string]Edge)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PutNode: puts a node in the graph
|
||||||
func (g *RootGraph) PutNode(name, label string, size int, shape Shape) error {
|
func (g *RootGraph) PutNode(name, label string, size int, shape Shape) error {
|
||||||
_, exists := g.nodes[name]
|
_, exists := g.nodes[name]
|
||||||
|
|
||||||
@ -95,7 +92,6 @@ func (g *RootGraph) PutNode(name, label string, size int, shape Shape) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutCluster: puts a cluster in the root graph
|
|
||||||
func (g *RootGraph) PutCluster(graph *Cluster) {
|
func (g *RootGraph) PutCluster(graph *Cluster) {
|
||||||
g.clusters[graph.Label] = graph
|
g.clusters[graph.Label] = graph
|
||||||
}
|
}
|
||||||
@ -117,7 +113,6 @@ func writeContituents[D Dottable](result *strings.Builder, elements ...D) error
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDOT: convert the root graph into dot format
|
|
||||||
func (g *RootGraph) GetDOT() (string, error) {
|
func (g *RootGraph) GetDOT() (string, error) {
|
||||||
var result strings.Builder
|
var result strings.Builder
|
||||||
|
|
||||||
@ -143,7 +138,7 @@ func (g *RootGraph) GetDOT() (string, error) {
|
|||||||
return result.String(), nil
|
return result.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetType: get the graph type. DIRECTED|UNDIRECTED
|
// GetType implements Graph.
|
||||||
func (r *RootGraph) GetType() GraphType {
|
func (r *RootGraph) GetType() GraphType {
|
||||||
return r.Type
|
return r.Type
|
||||||
}
|
}
|
||||||
@ -157,7 +152,7 @@ func constructEdge(graph Graph, name, label, from, to string) Edge {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddEdge: adds an edge between two nodes in the root graph
|
// AddEdge: adds an edge between two nodes in the graph
|
||||||
func (g *RootGraph) AddEdge(name string, label string, from string, to string) error {
|
func (g *RootGraph) AddEdge(name string, label string, from string, to string) error {
|
||||||
g.edges[name] = constructEdge(g, name, label, from, to)
|
g.edges[name] = constructEdge(g, name, label, from, to)
|
||||||
return nil
|
return nil
|
||||||
@ -171,18 +166,15 @@ func (n *Node) hash() int {
|
|||||||
return (int(h.Sum32()) % numColours) + 1
|
return (int(h.Sum32()) % numColours) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDOT: convert the node into DOT format
|
|
||||||
func (n *Node) GetDOT() (string, error) {
|
func (n *Node) GetDOT() (string, error) {
|
||||||
return fmt.Sprintf("node[label=\"%s\",shape=%s, style=\"filled\", fillcolor=%d, width=%d, height=%d, fixedsize=true] \"%s\";\n",
|
return fmt.Sprintf("node[label=\"%s\",shape=%s, style=\"filled\", fillcolor=%d, width=%d, height=%d, fixedsize=true] \"%s\";\n",
|
||||||
n.Label, n.Shape, n.hash(), n.Size, n.Size, n.Name), nil
|
n.Label, n.Shape, n.hash(), n.Size, n.Size, n.Name), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDOT: Convert a directed edge into dot format
|
|
||||||
func (e *DirectedEdge) GetDOT() (string, error) {
|
func (e *DirectedEdge) GetDOT() (string, error) {
|
||||||
return fmt.Sprintf("\"%s\" -> \"%s\" [label=\"%s\"];\n", e.From, e.To, e.Label), nil
|
return fmt.Sprintf("\"%s\" -> \"%s\" [label=\"%s\"];\n", e.From, e.To, e.Label), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDOT: convert an undirected edge into dot format
|
|
||||||
func (e *UndirectedEdge) GetDOT() (string, error) {
|
func (e *UndirectedEdge) GetDOT() (string, error) {
|
||||||
return fmt.Sprintf("\"%s\" -- \"%s\" [label=\"%s\"];\n", e.From, e.To, e.Label), nil
|
return fmt.Sprintf("\"%s\" -- \"%s\" [label=\"%s\"];\n", e.From, e.To, e.Label), nil
|
||||||
}
|
}
|
||||||
@ -206,7 +198,6 @@ func (g *Cluster) PutNode(name, label string, size int, shape Shape) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDOT: convert the cluster into dot format
|
|
||||||
func (g *Cluster) GetDOT() (string, error) {
|
func (g *Cluster) GetDOT() (string, error) {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
|
|
||||||
@ -221,12 +212,10 @@ func (g *Cluster) GetDOT() (string, error) {
|
|||||||
return builder.String(), nil
|
return builder.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetType: get the type of the subgraph (directed|undirected)
|
|
||||||
func (g *Cluster) GetType() GraphType {
|
func (g *Cluster) GetType() GraphType {
|
||||||
return g.Type
|
return g.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSubGraph: instantiate a new subgraph
|
|
||||||
func NewSubGraph(name string, label string, graphType GraphType) *Cluster {
|
func NewSubGraph(name string, label string, graphType GraphType) *Cluster {
|
||||||
return &Cluster{
|
return &Cluster{
|
||||||
Label: name,
|
Label: name,
|
||||||
@ -236,14 +225,3 @@ func NewSubGraph(name string, label string, graphType GraphType) *Cluster {
|
|||||||
edges: make(map[string]Edge),
|
edges: make(map[string]Edge),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGraph: create a new root graph
|
|
||||||
func NewGraph(label string, graphType GraphType) *RootGraph {
|
|
||||||
return &RootGraph{
|
|
||||||
Type: graphType,
|
|
||||||
Label: label,
|
|
||||||
clusters: map[string]*Cluster{},
|
|
||||||
nodes: make(map[string]*Node),
|
|
||||||
edges: make(map[string]Edge),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MeshGraphConverter converts a mesh to a graph
|
// MeshGraphConverter converts a mesh to a graph
|
||||||
|
@ -1,212 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.28.1
|
|
||||||
// protoc v3.21.12
|
|
||||||
// source: pkg/grpc/ctrlserver.proto
|
|
||||||
|
|
||||||
package rpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type GetMeshRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
MeshId string `protobuf:"bytes,1,opt,name=meshId,proto3" json:"meshId,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetMeshRequest) Reset() {
|
|
||||||
*x = GetMeshRequest{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_pkg_grpc_ctrlserver_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetMeshRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*GetMeshRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *GetMeshRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_pkg_grpc_ctrlserver_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use GetMeshRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*GetMeshRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_pkg_grpc_ctrlserver_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetMeshRequest) GetMeshId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.MeshId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetMeshReply struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Mesh []byte `protobuf:"bytes,1,opt,name=mesh,proto3" json:"mesh,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetMeshReply) Reset() {
|
|
||||||
*x = GetMeshReply{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_pkg_grpc_ctrlserver_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetMeshReply) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*GetMeshReply) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *GetMeshReply) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_pkg_grpc_ctrlserver_proto_msgTypes[1]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use GetMeshReply.ProtoReflect.Descriptor instead.
|
|
||||||
func (*GetMeshReply) Descriptor() ([]byte, []int) {
|
|
||||||
return file_pkg_grpc_ctrlserver_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *GetMeshReply) GetMesh() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.Mesh
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_pkg_grpc_ctrlserver_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_pkg_grpc_ctrlserver_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x19, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x74, 0x72, 0x6c, 0x73,
|
|
||||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x72, 0x70, 0x63,
|
|
||||||
0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x28, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x68,
|
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x65, 0x73, 0x68, 0x49,
|
|
||||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x73, 0x68, 0x49, 0x64, 0x22,
|
|
||||||
0x22, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
|
|
||||||
0x12, 0x0a, 0x04, 0x6d, 0x65, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6d,
|
|
||||||
0x65, 0x73, 0x68, 0x32, 0x4f, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x74, 0x72, 0x6c, 0x53,
|
|
||||||
0x65, 0x72, 0x76, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x68,
|
|
||||||
0x12, 0x18, 0x2e, 0x72, 0x70, 0x63, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4d,
|
|
||||||
0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x72, 0x70, 0x63,
|
|
||||||
0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x65, 0x73, 0x68, 0x52, 0x65, 0x70,
|
|
||||||
0x6c, 0x79, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x70, 0x63, 0x62,
|
|
||||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_pkg_grpc_ctrlserver_proto_rawDescOnce sync.Once
|
|
||||||
file_pkg_grpc_ctrlserver_proto_rawDescData = file_pkg_grpc_ctrlserver_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_pkg_grpc_ctrlserver_proto_rawDescGZIP() []byte {
|
|
||||||
file_pkg_grpc_ctrlserver_proto_rawDescOnce.Do(func() {
|
|
||||||
file_pkg_grpc_ctrlserver_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_grpc_ctrlserver_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_pkg_grpc_ctrlserver_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_pkg_grpc_ctrlserver_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_pkg_grpc_ctrlserver_proto_goTypes = []interface{}{
|
|
||||||
(*GetMeshRequest)(nil), // 0: rpctypes.GetMeshRequest
|
|
||||||
(*GetMeshReply)(nil), // 1: rpctypes.GetMeshReply
|
|
||||||
}
|
|
||||||
var file_pkg_grpc_ctrlserver_proto_depIdxs = []int32{
|
|
||||||
0, // 0: rpctypes.MeshCtrlServer.GetMesh:input_type -> rpctypes.GetMeshRequest
|
|
||||||
1, // 1: rpctypes.MeshCtrlServer.GetMesh:output_type -> rpctypes.GetMeshReply
|
|
||||||
1, // [1:2] is the sub-list for method output_type
|
|
||||||
0, // [0:1] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_pkg_grpc_ctrlserver_proto_init() }
|
|
||||||
func file_pkg_grpc_ctrlserver_proto_init() {
|
|
||||||
if File_pkg_grpc_ctrlserver_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_pkg_grpc_ctrlserver_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*GetMeshRequest); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_pkg_grpc_ctrlserver_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*GetMeshReply); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_pkg_grpc_ctrlserver_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 2,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 1,
|
|
||||||
},
|
|
||||||
GoTypes: file_pkg_grpc_ctrlserver_proto_goTypes,
|
|
||||||
DependencyIndexes: file_pkg_grpc_ctrlserver_proto_depIdxs,
|
|
||||||
MessageInfos: file_pkg_grpc_ctrlserver_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_pkg_grpc_ctrlserver_proto = out.File
|
|
||||||
file_pkg_grpc_ctrlserver_proto_rawDesc = nil
|
|
||||||
file_pkg_grpc_ctrlserver_proto_goTypes = nil
|
|
||||||
file_pkg_grpc_ctrlserver_proto_depIdxs = nil
|
|
||||||
}
|
|
18
pkg/grpc/ctrlserver/authentication.proto
Normal file
18
pkg/grpc/ctrlserver/authentication.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package rpctypes;
|
||||||
|
|
||||||
|
option go_package = "pkg/rpc";
|
||||||
|
|
||||||
|
service Authentication {
|
||||||
|
rpc JoinMesh(JoinAuthMeshRequest) returns (JoinAuthMeshReply) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
message JoinAuthMeshRequest {
|
||||||
|
string meshId = 1;
|
||||||
|
string alias = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message JoinAuthMeshReply {
|
||||||
|
bool success = 1;
|
||||||
|
optional string token = 2;
|
||||||
|
}
|
@ -4,9 +4,18 @@ package syncservice;
|
|||||||
option go_package = "pkg/rpc";
|
option go_package = "pkg/rpc";
|
||||||
|
|
||||||
service SyncService {
|
service SyncService {
|
||||||
|
rpc GetConf(GetConfRequest) returns (GetConfReply) {}
|
||||||
rpc SyncMesh(stream SyncMeshRequest) returns (stream SyncMeshReply) {}
|
rpc SyncMesh(stream SyncMeshRequest) returns (stream SyncMeshReply) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetConfRequest {
|
||||||
|
string meshId = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetConfReply {
|
||||||
|
bytes mesh = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message SyncMeshRequest {
|
message SyncMeshRequest {
|
||||||
string meshId = 1;
|
string meshId = 1;
|
||||||
bytes changes = 2;
|
bytes changes = 2;
|
@ -1,105 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.2.0
|
|
||||||
// - protoc v3.21.12
|
|
||||||
// source: pkg/grpc/ctrlserver.proto
|
|
||||||
|
|
||||||
package rpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the grpc package it is being compiled against.
|
|
||||||
// Requires gRPC-Go v1.32.0 or later.
|
|
||||||
const _ = grpc.SupportPackageIsVersion7
|
|
||||||
|
|
||||||
// MeshCtrlServerClient is the client API for MeshCtrlServer service.
|
|
||||||
//
|
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
||||||
type MeshCtrlServerClient interface {
|
|
||||||
GetMesh(ctx context.Context, in *GetMeshRequest, opts ...grpc.CallOption) (*GetMeshReply, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type meshCtrlServerClient struct {
|
|
||||||
cc grpc.ClientConnInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMeshCtrlServerClient(cc grpc.ClientConnInterface) MeshCtrlServerClient {
|
|
||||||
return &meshCtrlServerClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *meshCtrlServerClient) GetMesh(ctx context.Context, in *GetMeshRequest, opts ...grpc.CallOption) (*GetMeshReply, error) {
|
|
||||||
out := new(GetMeshReply)
|
|
||||||
err := c.cc.Invoke(ctx, "/rpctypes.MeshCtrlServer/GetMesh", in, out, opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeshCtrlServerServer is the server API for MeshCtrlServer service.
|
|
||||||
// All implementations must embed UnimplementedMeshCtrlServerServer
|
|
||||||
// for forward compatibility
|
|
||||||
type MeshCtrlServerServer interface {
|
|
||||||
GetMesh(context.Context, *GetMeshRequest) (*GetMeshReply, error)
|
|
||||||
mustEmbedUnimplementedMeshCtrlServerServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnimplementedMeshCtrlServerServer must be embedded to have forward compatible implementations.
|
|
||||||
type UnimplementedMeshCtrlServerServer struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (UnimplementedMeshCtrlServerServer) GetMesh(context.Context, *GetMeshRequest) (*GetMeshReply, error) {
|
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetMesh not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedMeshCtrlServerServer) mustEmbedUnimplementedMeshCtrlServerServer() {}
|
|
||||||
|
|
||||||
// UnsafeMeshCtrlServerServer may be embedded to opt out of forward compatibility for this service.
|
|
||||||
// Use of this interface is not recommended, as added methods to MeshCtrlServerServer will
|
|
||||||
// result in compilation errors.
|
|
||||||
type UnsafeMeshCtrlServerServer interface {
|
|
||||||
mustEmbedUnimplementedMeshCtrlServerServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterMeshCtrlServerServer(s grpc.ServiceRegistrar, srv MeshCtrlServerServer) {
|
|
||||||
s.RegisterService(&MeshCtrlServer_ServiceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _MeshCtrlServer_GetMesh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(GetMeshRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(MeshCtrlServerServer).GetMesh(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: "/rpctypes.MeshCtrlServer/GetMesh",
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(MeshCtrlServerServer).GetMesh(ctx, req.(*GetMeshRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MeshCtrlServer_ServiceDesc is the grpc.ServiceDesc for MeshCtrlServer service.
|
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
|
||||||
// and not to be introspected or modified (even as a copy)
|
|
||||||
var MeshCtrlServer_ServiceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "rpctypes.MeshCtrlServer",
|
|
||||||
HandlerType: (*MeshCtrlServerServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{
|
|
||||||
{
|
|
||||||
MethodName: "GetMesh",
|
|
||||||
Handler: _MeshCtrlServer_GetMesh_Handler,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Streams: []grpc.StreamDesc{},
|
|
||||||
Metadata: "pkg/grpc/ctrlserver.proto",
|
|
||||||
}
|
|
@ -1,233 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.28.1
|
|
||||||
// protoc v3.21.12
|
|
||||||
// source: pkg/grpc/syncservice.proto
|
|
||||||
|
|
||||||
package rpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type SyncMeshRequest struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
MeshId string `protobuf:"bytes,1,opt,name=meshId,proto3" json:"meshId,omitempty"`
|
|
||||||
Changes []byte `protobuf:"bytes,2,opt,name=changes,proto3" json:"changes,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SyncMeshRequest) Reset() {
|
|
||||||
*x = SyncMeshRequest{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_pkg_grpc_syncservice_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SyncMeshRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*SyncMeshRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *SyncMeshRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_pkg_grpc_syncservice_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SyncMeshRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*SyncMeshRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_pkg_grpc_syncservice_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SyncMeshRequest) GetMeshId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.MeshId
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SyncMeshRequest) GetChanges() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.Changes
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type SyncMeshReply struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
|
||||||
Changes []byte `protobuf:"bytes,2,opt,name=changes,proto3" json:"changes,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SyncMeshReply) Reset() {
|
|
||||||
*x = SyncMeshReply{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_pkg_grpc_syncservice_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SyncMeshReply) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*SyncMeshReply) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *SyncMeshReply) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_pkg_grpc_syncservice_proto_msgTypes[1]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SyncMeshReply.ProtoReflect.Descriptor instead.
|
|
||||||
func (*SyncMeshReply) Descriptor() ([]byte, []int) {
|
|
||||||
return file_pkg_grpc_syncservice_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SyncMeshReply) GetSuccess() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Success
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SyncMeshReply) GetChanges() []byte {
|
|
||||||
if x != nil {
|
|
||||||
return x.Changes
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_pkg_grpc_syncservice_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_pkg_grpc_syncservice_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x1a, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x79, 0x6e, 0x63, 0x73,
|
|
||||||
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x73, 0x79,
|
|
||||||
0x6e, 0x63, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x43, 0x0a, 0x0f, 0x53, 0x79, 0x6e,
|
|
||||||
0x63, 0x4d, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06,
|
|
||||||
0x6d, 0x65, 0x73, 0x68, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65,
|
|
||||||
0x73, 0x68, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18,
|
|
||||||
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x22, 0x43,
|
|
||||||
0x0a, 0x0d, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12,
|
|
||||||
0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08,
|
|
||||||
0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61,
|
|
||||||
0x6e, 0x67, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e,
|
|
||||||
0x67, 0x65, 0x73, 0x32, 0x59, 0x0a, 0x0b, 0x53, 0x79, 0x6e, 0x63, 0x53, 0x65, 0x72, 0x76, 0x69,
|
|
||||||
0x63, 0x65, 0x12, 0x4a, 0x0a, 0x08, 0x53, 0x79, 0x6e, 0x63, 0x4d, 0x65, 0x73, 0x68, 0x12, 0x1c,
|
|
||||||
0x2e, 0x73, 0x79, 0x6e, 0x63, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e,
|
|
||||||
0x63, 0x4d, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x73,
|
|
||||||
0x79, 0x6e, 0x63, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x79, 0x6e, 0x63, 0x4d,
|
|
||||||
0x65, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x09,
|
|
||||||
0x5a, 0x07, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
|
||||||
0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_pkg_grpc_syncservice_proto_rawDescOnce sync.Once
|
|
||||||
file_pkg_grpc_syncservice_proto_rawDescData = file_pkg_grpc_syncservice_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_pkg_grpc_syncservice_proto_rawDescGZIP() []byte {
|
|
||||||
file_pkg_grpc_syncservice_proto_rawDescOnce.Do(func() {
|
|
||||||
file_pkg_grpc_syncservice_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_grpc_syncservice_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_pkg_grpc_syncservice_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_pkg_grpc_syncservice_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_pkg_grpc_syncservice_proto_goTypes = []interface{}{
|
|
||||||
(*SyncMeshRequest)(nil), // 0: syncservice.SyncMeshRequest
|
|
||||||
(*SyncMeshReply)(nil), // 1: syncservice.SyncMeshReply
|
|
||||||
}
|
|
||||||
var file_pkg_grpc_syncservice_proto_depIdxs = []int32{
|
|
||||||
0, // 0: syncservice.SyncService.SyncMesh:input_type -> syncservice.SyncMeshRequest
|
|
||||||
1, // 1: syncservice.SyncService.SyncMesh:output_type -> syncservice.SyncMeshReply
|
|
||||||
1, // [1:2] is the sub-list for method output_type
|
|
||||||
0, // [0:1] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_pkg_grpc_syncservice_proto_init() }
|
|
||||||
func file_pkg_grpc_syncservice_proto_init() {
|
|
||||||
if File_pkg_grpc_syncservice_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_pkg_grpc_syncservice_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*SyncMeshRequest); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_pkg_grpc_syncservice_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*SyncMeshReply); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_pkg_grpc_syncservice_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 2,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 1,
|
|
||||||
},
|
|
||||||
GoTypes: file_pkg_grpc_syncservice_proto_goTypes,
|
|
||||||
DependencyIndexes: file_pkg_grpc_syncservice_proto_depIdxs,
|
|
||||||
MessageInfos: file_pkg_grpc_syncservice_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_pkg_grpc_syncservice_proto = out.File
|
|
||||||
file_pkg_grpc_syncservice_proto_rawDesc = nil
|
|
||||||
file_pkg_grpc_syncservice_proto_goTypes = nil
|
|
||||||
file_pkg_grpc_syncservice_proto_depIdxs = nil
|
|
||||||
}
|
|
@ -1,137 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.2.0
|
|
||||||
// - protoc v3.21.12
|
|
||||||
// source: pkg/grpc/syncservice.proto
|
|
||||||
|
|
||||||
package rpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the grpc package it is being compiled against.
|
|
||||||
// Requires gRPC-Go v1.32.0 or later.
|
|
||||||
const _ = grpc.SupportPackageIsVersion7
|
|
||||||
|
|
||||||
// SyncServiceClient is the client API for SyncService service.
|
|
||||||
//
|
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
||||||
type SyncServiceClient interface {
|
|
||||||
SyncMesh(ctx context.Context, opts ...grpc.CallOption) (SyncService_SyncMeshClient, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type syncServiceClient struct {
|
|
||||||
cc grpc.ClientConnInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSyncServiceClient(cc grpc.ClientConnInterface) SyncServiceClient {
|
|
||||||
return &syncServiceClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *syncServiceClient) SyncMesh(ctx context.Context, opts ...grpc.CallOption) (SyncService_SyncMeshClient, error) {
|
|
||||||
stream, err := c.cc.NewStream(ctx, &SyncService_ServiceDesc.Streams[0], "/syncservice.SyncService/SyncMesh", opts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
x := &syncServiceSyncMeshClient{stream}
|
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type SyncService_SyncMeshClient interface {
|
|
||||||
Send(*SyncMeshRequest) error
|
|
||||||
Recv() (*SyncMeshReply, error)
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type syncServiceSyncMeshClient struct {
|
|
||||||
grpc.ClientStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *syncServiceSyncMeshClient) Send(m *SyncMeshRequest) error {
|
|
||||||
return x.ClientStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *syncServiceSyncMeshClient) Recv() (*SyncMeshReply, error) {
|
|
||||||
m := new(SyncMeshReply)
|
|
||||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncServiceServer is the server API for SyncService service.
|
|
||||||
// All implementations must embed UnimplementedSyncServiceServer
|
|
||||||
// for forward compatibility
|
|
||||||
type SyncServiceServer interface {
|
|
||||||
SyncMesh(SyncService_SyncMeshServer) error
|
|
||||||
mustEmbedUnimplementedSyncServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnimplementedSyncServiceServer must be embedded to have forward compatible implementations.
|
|
||||||
type UnimplementedSyncServiceServer struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (UnimplementedSyncServiceServer) SyncMesh(SyncService_SyncMeshServer) error {
|
|
||||||
return status.Errorf(codes.Unimplemented, "method SyncMesh not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedSyncServiceServer) mustEmbedUnimplementedSyncServiceServer() {}
|
|
||||||
|
|
||||||
// UnsafeSyncServiceServer may be embedded to opt out of forward compatibility for this service.
|
|
||||||
// Use of this interface is not recommended, as added methods to SyncServiceServer will
|
|
||||||
// result in compilation errors.
|
|
||||||
type UnsafeSyncServiceServer interface {
|
|
||||||
mustEmbedUnimplementedSyncServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterSyncServiceServer(s grpc.ServiceRegistrar, srv SyncServiceServer) {
|
|
||||||
s.RegisterService(&SyncService_ServiceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _SyncService_SyncMesh_Handler(srv interface{}, stream grpc.ServerStream) error {
|
|
||||||
return srv.(SyncServiceServer).SyncMesh(&syncServiceSyncMeshServer{stream})
|
|
||||||
}
|
|
||||||
|
|
||||||
type SyncService_SyncMeshServer interface {
|
|
||||||
Send(*SyncMeshReply) error
|
|
||||||
Recv() (*SyncMeshRequest, error)
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
type syncServiceSyncMeshServer struct {
|
|
||||||
grpc.ServerStream
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *syncServiceSyncMeshServer) Send(m *SyncMeshReply) error {
|
|
||||||
return x.ServerStream.SendMsg(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *syncServiceSyncMeshServer) Recv() (*SyncMeshRequest, error) {
|
|
||||||
m := new(SyncMeshRequest)
|
|
||||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncService_ServiceDesc is the grpc.ServiceDesc for SyncService service.
|
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
|
||||||
// and not to be introspected or modified (even as a copy)
|
|
||||||
var SyncService_ServiceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "syncservice.SyncService",
|
|
||||||
HandlerType: (*SyncServiceServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{},
|
|
||||||
Streams: []grpc.StreamDesc{
|
|
||||||
{
|
|
||||||
StreamName: "SyncMesh",
|
|
||||||
Handler: _SyncService_SyncMesh_Handler,
|
|
||||||
ServerStreams: true,
|
|
||||||
ClientStreams: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Metadata: "pkg/grpc/syncservice.proto",
|
|
||||||
}
|
|
@ -1,7 +1,8 @@
|
|||||||
package ip
|
package ip
|
||||||
|
|
||||||
// Generates a CGA see RFC 3972
|
/*
|
||||||
// https://datatracker.ietf.org/doc/html/rfc3972
|
* Use a WireGuard public key to generate a unique interface ID
|
||||||
|
*/
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -21,23 +22,19 @@ const (
|
|||||||
InterfaceIdLen = 8
|
InterfaceIdLen = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
// CGAParameters: parameters used to create a new cryotpgraphically generated
|
/*
|
||||||
// address
|
* Cga parameters used to generate an IPV6 interface ID
|
||||||
|
*/
|
||||||
type CgaParameters struct {
|
type CgaParameters struct {
|
||||||
Modifier [ModifierLength]byte
|
Modifier [ModifierLength]byte
|
||||||
// SubnetPrefix: prefix of the subnetwork
|
|
||||||
SubnetPrefix [2 * InterfaceIdLen]byte
|
SubnetPrefix [2 * InterfaceIdLen]byte
|
||||||
// CollisionCount: total number of times we have atempted to generate a porefix
|
|
||||||
CollisionCount uint8
|
CollisionCount uint8
|
||||||
// PublicKey: WireGuard public key of our interface
|
|
||||||
PublicKey wgtypes.Key
|
PublicKey wgtypes.Key
|
||||||
// interfaceId: the generated interfaceId
|
|
||||||
interfaceId [2 * InterfaceIdLen]byte
|
interfaceId [2 * InterfaceIdLen]byte
|
||||||
// flag: represents whether or not an IP address has been generated
|
|
||||||
flag byte
|
flag byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCga(key wgtypes.Key, collisionCount uint8, subnetPrefix [2 * InterfaceIdLen]byte) (*CgaParameters, error) {
|
func NewCga(key wgtypes.Key, subnetPrefix [2 * InterfaceIdLen]byte) (*CgaParameters, error) {
|
||||||
var params CgaParameters
|
var params CgaParameters
|
||||||
|
|
||||||
_, err := rand.Read(params.Modifier[:])
|
_, err := rand.Read(params.Modifier[:])
|
||||||
@ -48,10 +45,25 @@ func NewCga(key wgtypes.Key, collisionCount uint8, subnetPrefix [2 * InterfaceId
|
|||||||
|
|
||||||
params.PublicKey = key
|
params.PublicKey = key
|
||||||
params.SubnetPrefix = subnetPrefix
|
params.SubnetPrefix = subnetPrefix
|
||||||
params.CollisionCount = collisionCount
|
|
||||||
return ¶ms, nil
|
return ¶ms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CgaParameters) generateHash2() []byte {
|
||||||
|
var byteVal [hash2Length]byte
|
||||||
|
|
||||||
|
for i := 0; i < ModifierLength; i++ {
|
||||||
|
byteVal[i] = c.Modifier[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < wgtypes.KeyLen; i++ {
|
||||||
|
byteVal[ModifierLength+ZeroLength+i] = c.PublicKey[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := sha1.Sum(byteVal[:])
|
||||||
|
|
||||||
|
return hash[:Hash2Prefix]
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CgaParameters) generateHash1() []byte {
|
func (c *CgaParameters) generateHash1() []byte {
|
||||||
var byteVal [hash1Length]byte
|
var byteVal [hash1Length]byte
|
||||||
|
|
||||||
@ -66,6 +78,7 @@ func (c *CgaParameters) generateHash1() []byte {
|
|||||||
byteVal[hash1Length-1] = c.CollisionCount
|
byteVal[hash1Length-1] = c.CollisionCount
|
||||||
|
|
||||||
hash := sha1.Sum(byteVal[:])
|
hash := sha1.Sum(byteVal[:])
|
||||||
|
|
||||||
return hash[:Hash1Prefix]
|
return hash[:Hash1Prefix]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,6 +90,9 @@ func clearBit(num, pos int) byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *CgaParameters) generateInterface() []byte {
|
func (c *CgaParameters) generateInterface() []byte {
|
||||||
|
// TODO: On duplicate address detection increment collision.
|
||||||
|
// Also incorporate SEC
|
||||||
|
|
||||||
hash1 := c.generateHash1()
|
hash1 := c.generateHash1()
|
||||||
|
|
||||||
var interfaceId []byte = make([]byte, InterfaceIdLen)
|
var interfaceId []byte = make([]byte, InterfaceIdLen)
|
||||||
@ -85,6 +101,7 @@ func (c *CgaParameters) generateInterface() []byte {
|
|||||||
|
|
||||||
interfaceId[0] = clearBit(int(interfaceId[0]), 6)
|
interfaceId[0] = clearBit(int(interfaceId[0]), 6)
|
||||||
interfaceId[0] = clearBit(int(interfaceId[1]), 7)
|
interfaceId[0] = clearBit(int(interfaceId[1]), 7)
|
||||||
|
|
||||||
return interfaceId
|
return interfaceId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IPAllocator: abstracts the process of creating an IP address
|
|
||||||
type IPAllocator interface {
|
type IPAllocator interface {
|
||||||
GetIP(key wgtypes.Key, meshId string, collisionCount uint8) (net.IP, error)
|
GetIP(key wgtypes.Key, meshId string) (net.IP, error)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ULABuilder: Create a new ULA in WireGuard
|
|
||||||
type ULABuilder struct{}
|
type ULABuilder struct{}
|
||||||
|
|
||||||
func getMeshPrefix(meshId string) [16]byte {
|
func getMeshPrefix(meshId string) [16]byte {
|
||||||
@ -40,10 +39,10 @@ func (u *ULABuilder) GetIPNet(meshId string) (*net.IPNet, error) {
|
|||||||
return net, nil
|
return net, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ULABuilder) GetIP(key wgtypes.Key, meshId string, collisionCount uint8) (net.IP, error) {
|
func (u *ULABuilder) GetIP(key wgtypes.Key, meshId string) (net.IP, error) {
|
||||||
ulaPrefix := getMeshPrefix(meshId)
|
ulaPrefix := getMeshPrefix(meshId)
|
||||||
|
|
||||||
c, err := NewCga(key, collisionCount, ulaPrefix)
|
c, err := NewCga(key, ulaPrefix)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
132
pkg/ipc/ipc.go
132
pkg/ipc/ipc.go
@ -5,27 +5,11 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/rpc"
|
"net/rpc"
|
||||||
ipcRPC "net/rpc"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
)
|
)
|
||||||
|
|
||||||
const SockAddr = "/tmp/smeg.sock"
|
|
||||||
|
|
||||||
type MeshIpc interface {
|
|
||||||
CreateMesh(args *NewMeshArgs, reply *string) error
|
|
||||||
ListMeshes(name string, reply *ListMeshReply) error
|
|
||||||
JoinMesh(args *JoinMeshArgs, reply *string) error
|
|
||||||
LeaveMesh(meshId string, reply *string) error
|
|
||||||
GetMesh(meshId string, reply *GetMeshReply) error
|
|
||||||
Query(query QueryMesh, reply *string) error
|
|
||||||
PutDescription(args PutDescriptionArgs, reply *string) error
|
|
||||||
PutAlias(args PutAliasArgs, reply *string) error
|
|
||||||
PutService(args PutServiceArgs, reply *string) error
|
|
||||||
DeleteService(args DeleteServiceArgs, reply *string) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// WireGuardArgs are provided args specific to WireGuard
|
// WireGuardArgs are provided args specific to WireGuard
|
||||||
type WireGuardArgs struct {
|
type WireGuardArgs struct {
|
||||||
// WgPort is the WireGuard port to expose
|
// WgPort is the WireGuard port to expose
|
||||||
@ -55,141 +39,43 @@ type JoinMeshArgs struct {
|
|||||||
// MeshId is the ID of the mesh to join
|
// MeshId is the ID of the mesh to join
|
||||||
MeshId string
|
MeshId string
|
||||||
// IpAddress is a routable IP in another mesh
|
// IpAddress is a routable IP in another mesh
|
||||||
IpAddress string
|
IpAdress string
|
||||||
// WgArgs is the WireGuard parameters to use.
|
// WgArgs is the WireGuard parameters to use.
|
||||||
WgArgs WireGuardArgs
|
WgArgs WireGuardArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutServiceArgs: args to place a service into the data store
|
|
||||||
type PutServiceArgs struct {
|
type PutServiceArgs struct {
|
||||||
Service string
|
Service string
|
||||||
Value string
|
Value string
|
||||||
MeshId string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteServiceArgs: args to remove a service from the data store
|
|
||||||
type DeleteServiceArgs struct {
|
|
||||||
Service string
|
|
||||||
MeshId string
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutAliasArgs: args to assign an alias to a node
|
|
||||||
type PutAliasArgs struct {
|
|
||||||
// Alias: represents the alias of the node
|
|
||||||
Alias string
|
|
||||||
// MeshId: represents the meshID of the node
|
|
||||||
MeshId string
|
|
||||||
}
|
|
||||||
|
|
||||||
// PutDescriptionArgs: args to assign a description to a node
|
|
||||||
type PutDescriptionArgs struct {
|
|
||||||
// Description: descriptio to add to the network
|
|
||||||
Description string
|
|
||||||
// MeshID to add to the mesh network
|
|
||||||
MeshId string
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMeshReply: ipc reply to get the mesh network
|
|
||||||
type GetMeshReply struct {
|
type GetMeshReply struct {
|
||||||
Nodes []ctrlserver.MeshNode
|
Nodes []ctrlserver.MeshNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMeshReply: ipc reply of the networks the node is part of
|
|
||||||
type ListMeshReply struct {
|
type ListMeshReply struct {
|
||||||
Meshes []string
|
Meshes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Querymesh: ipc args to query a mesh network
|
|
||||||
type QueryMesh struct {
|
type QueryMesh struct {
|
||||||
// MeshId: id of the mesh to query
|
|
||||||
MeshId string
|
MeshId string
|
||||||
// JMESPath: query string to query
|
Query string
|
||||||
Query string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientIpc: Framework to invoke ipc calls to the daemon
|
type MeshIpc interface {
|
||||||
type ClientIpc interface {
|
|
||||||
// CreateMesh: create a mesh network, return an error if the operation failed
|
|
||||||
CreateMesh(args *NewMeshArgs, reply *string) error
|
CreateMesh(args *NewMeshArgs, reply *string) error
|
||||||
// ListMesh: list mesh network the node is a part of, return an error if the operation failed
|
ListMeshes(name string, reply *ListMeshReply) error
|
||||||
ListMeshes(args *ListMeshReply, reply *string) error
|
|
||||||
// JoinMesh: join a mesh network return an error if the operation failed
|
|
||||||
JoinMesh(args JoinMeshArgs, reply *string) error
|
JoinMesh(args JoinMeshArgs, reply *string) error
|
||||||
// LeaveMesh: leave a mesh network, return an error if the operation failed
|
|
||||||
LeaveMesh(meshId string, reply *string) error
|
LeaveMesh(meshId string, reply *string) error
|
||||||
// GetMesh: get the given mesh network, return an error if the operation failed
|
|
||||||
GetMesh(meshId string, reply *GetMeshReply) error
|
GetMesh(meshId string, reply *GetMeshReply) error
|
||||||
// Query: query the given mesh network
|
|
||||||
Query(query QueryMesh, reply *string) error
|
Query(query QueryMesh, reply *string) error
|
||||||
// PutDescription: assign a description to yourself
|
PutDescription(description string, reply *string) error
|
||||||
PutDescription(args PutDescriptionArgs, reply *string) error
|
PutAlias(alias string, reply *string) error
|
||||||
// PutAlias: assign an alias to yourself
|
|
||||||
PutAlias(args PutAliasArgs, reply *string) error
|
|
||||||
// PutService: assign a service to yourself
|
|
||||||
PutService(args PutServiceArgs, reply *string) error
|
PutService(args PutServiceArgs, reply *string) error
|
||||||
// DeleteService: retract a service
|
DeleteService(service string, reply *string) error
|
||||||
DeleteService(args DeleteServiceArgs, reply *string) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SmegmeshIpc struct {
|
const SockAddr = "/tmp/wgmesh_ipc.sock"
|
||||||
client *ipcRPC.Client
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewClientIpc() (*SmegmeshIpc, error) {
|
|
||||||
client, err := ipcRPC.DialHTTP("unix", SockAddr)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &SmegmeshIpc{
|
|
||||||
client: client,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) CreateMesh(args *NewMeshArgs, reply *string) error {
|
|
||||||
return c.client.Call("IpcHandler.CreateMesh", args, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) ListMeshes(reply *ListMeshReply) error {
|
|
||||||
return c.client.Call("IpcHandler.ListMeshes", "", reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) JoinMesh(args JoinMeshArgs, reply *string) error {
|
|
||||||
return c.client.Call("IpcHandler.JoinMesh", &args, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) LeaveMesh(meshId string, reply *string) error {
|
|
||||||
return c.client.Call("IpcHandler.LeaveMesh", &meshId, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) GetMesh(meshId string, reply *GetMeshReply) error {
|
|
||||||
return c.client.Call("IpcHandler.GetMesh", &meshId, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) Query(query QueryMesh, reply *string) error {
|
|
||||||
return c.client.Call("IpcHandler.Query", &query, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) PutDescription(args PutDescriptionArgs, reply *string) error {
|
|
||||||
return c.client.Call("IpcHandler.PutDescription", &args, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) PutAlias(args PutAliasArgs, reply *string) error {
|
|
||||||
return c.client.Call("IpcHandler.PutAlias", &args, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) PutService(args PutServiceArgs, reply *string) error {
|
|
||||||
return c.client.Call("IpcHandler.PutService", &args, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) DeleteService(args DeleteServiceArgs, reply *string) error {
|
|
||||||
return c.client.Call("IpcHandler.DeleteService", &args, reply)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *SmegmeshIpc) Close() error {
|
|
||||||
return c.client.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunIpcHandler(server MeshIpc) error {
|
func RunIpcHandler(server MeshIpc) error {
|
||||||
if err := os.RemoveAll(SockAddr); err != nil {
|
if err := os.RemoveAll(SockAddr); err != nil {
|
||||||
|
@ -17,7 +17,7 @@ func HashString(value string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConsistentHash implementation. Traverse the values until we find a key
|
// ConsistentHash implementation. Traverse the values until we find a key
|
||||||
// greater than ours.
|
// less than ours.
|
||||||
func ConsistentHash[V any, K any](values []V, client K, bucketFunc func(V) int, keyFunc func(K) int) V {
|
func ConsistentHash[V any, K any](values []V, client K, bucketFunc func(V) int, keyFunc func(K) int) V {
|
||||||
if len(values) == 0 {
|
if len(values) == 0 {
|
||||||
panic("values is empty")
|
panic("values is empty")
|
||||||
@ -36,13 +36,11 @@ func ConsistentHash[V any, K any](values []V, client K, bucketFunc func(V) int,
|
|||||||
|
|
||||||
ourKey := keyFunc(client)
|
ourKey := keyFunc(client)
|
||||||
|
|
||||||
idx := sort.Search(len(vs), func(i int) bool {
|
for _, record := range vs {
|
||||||
return vs[i].value >= ourKey
|
if ourKey < record.value {
|
||||||
})
|
return record.record
|
||||||
|
}
|
||||||
if idx == len(vs) {
|
|
||||||
return vs[0].record
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vs[idx].record
|
return vs[0].record
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package lib
|
|||||||
import (
|
import (
|
||||||
"github.com/anandvarma/namegen"
|
"github.com/anandvarma/namegen"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/lithammer/shortuuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// IdGenerator generates unique ids
|
// IdGenerator generates unique ids
|
||||||
@ -20,14 +19,6 @@ func (g *UUIDGenerator) GetId() (string, error) {
|
|||||||
return id.String(), nil
|
return id.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type ShortIDGenerator struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *ShortIDGenerator) GetId() (string, error) {
|
|
||||||
id := shortuuid.New()
|
|
||||||
return id, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type IDNameGenerator struct {
|
type IDNameGenerator struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,21 +6,27 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/jsimonetti/rtnetlink"
|
"github.com/jsimonetti/rtnetlink"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Maximum MTU to assin to WireGuard
|
|
||||||
// This isn't configurable
|
|
||||||
const WIREGUARD_MTU = 1420
|
|
||||||
|
|
||||||
// RtNetlinkConfig: represents an rtnetlkink configuration instance
|
|
||||||
type RtNetlinkConfig struct {
|
type RtNetlinkConfig struct {
|
||||||
// conn: connection to the rtnetlink API
|
|
||||||
conn *rtnetlink.Conn
|
conn *rtnetlink.Conn
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateLink: Create a netlink interface if it does not exist. ifName is the name of the netlink interface
|
func NewRtNetlinkConfig() (*RtNetlinkConfig, error) {
|
||||||
|
conn, err := rtnetlink.Dial(nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &RtNetlinkConfig{conn: conn}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const WIREGUARD_MTU = 1420
|
||||||
|
|
||||||
|
// Create a netlink interface if it does not exist. ifName is the name of the netlink interface
|
||||||
func (c *RtNetlinkConfig) CreateLink(ifName string) error {
|
func (c *RtNetlinkConfig) CreateLink(ifName string) error {
|
||||||
_, err := net.InterfaceByName(ifName)
|
_, err := net.InterfaceByName(ifName)
|
||||||
|
|
||||||
@ -45,7 +51,7 @@ func (c *RtNetlinkConfig) CreateLink(ifName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteLink: delete the specified interface
|
// Delete link delete the specified interface
|
||||||
func (c *RtNetlinkConfig) DeleteLink(ifName string) error {
|
func (c *RtNetlinkConfig) DeleteLink(ifName string) error {
|
||||||
iface, err := net.InterfaceByName(ifName)
|
iface, err := net.InterfaceByName(ifName)
|
||||||
|
|
||||||
@ -62,7 +68,7 @@ func (c *RtNetlinkConfig) DeleteLink(ifName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAddress: adds an address to the given interface.
|
// AddAddress adds an address to the given interface.
|
||||||
func (c *RtNetlinkConfig) AddAddress(ifName string, address string) error {
|
func (c *RtNetlinkConfig) AddAddress(ifName string, address string) error {
|
||||||
iface, err := net.InterfaceByName(ifName)
|
iface, err := net.InterfaceByName(ifName)
|
||||||
|
|
||||||
@ -171,7 +177,7 @@ func (c *RtNetlinkConfig) AddRoute(ifName string, route Route) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRoute: deletes routes with the gateway and destination
|
// DeleteRoute deletes routes with the gateway and destination
|
||||||
func (c *RtNetlinkConfig) DeleteRoute(ifName string, route Route) error {
|
func (c *RtNetlinkConfig) DeleteRoute(ifName string, route Route) error {
|
||||||
iface, err := net.InterfaceByName(ifName)
|
iface, err := net.InterfaceByName(ifName)
|
||||||
|
|
||||||
@ -213,7 +219,6 @@ func (c *RtNetlinkConfig) DeleteRoute(ifName string, route Route) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// route: represents a rout to add to the RIB
|
|
||||||
type Route struct {
|
type Route struct {
|
||||||
Gateway net.IP
|
Gateway net.IP
|
||||||
Destination net.IPNet
|
Destination net.IPNet
|
||||||
@ -227,7 +232,7 @@ func (r1 Route) equal(r2 Route) bool {
|
|||||||
(mask1Ones == 0 && mask2Ones == 0 || r1.Destination.IP.Equal(r2.Destination.IP))
|
(mask1Ones == 0 && mask2Ones == 0 || r1.Destination.IP.Equal(r2.Destination.IP))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRoutes: deletes all routes not in exclude on the given interface
|
// DeleteRoutes deletes all routes not in exclude
|
||||||
func (c *RtNetlinkConfig) DeleteRoutes(ifName string, family uint8, exclude ...Route) error {
|
func (c *RtNetlinkConfig) DeleteRoutes(ifName string, family uint8, exclude ...Route) error {
|
||||||
routes, err := c.listRoutes(ifName, family)
|
routes, err := c.listRoutes(ifName, family)
|
||||||
|
|
||||||
@ -277,7 +282,7 @@ func (c *RtNetlinkConfig) DeleteRoutes(ifName string, family uint8, exclude ...R
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// listRoutes: lists all routes on the interface
|
// listRoutes lists all routes on the interface
|
||||||
func (c *RtNetlinkConfig) listRoutes(ifName string, family uint8) ([]rtnetlink.RouteMessage, error) {
|
func (c *RtNetlinkConfig) listRoutes(ifName string, family uint8) ([]rtnetlink.RouteMessage, error) {
|
||||||
iface, err := net.InterfaceByName(ifName)
|
iface, err := net.InterfaceByName(ifName)
|
||||||
|
|
||||||
@ -299,18 +304,6 @@ func (c *RtNetlinkConfig) listRoutes(ifName string, family uint8) ([]rtnetlink.R
|
|||||||
return routes, nil
|
return routes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close: close the Rtnetlink API
|
|
||||||
func (c *RtNetlinkConfig) Close() error {
|
func (c *RtNetlinkConfig) Close() error {
|
||||||
return c.conn.Close()
|
return c.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// newRtNetlinkConfig: connect to the RtnetlinkAPI
|
|
||||||
func NewRtNetlinkConfig() (*RtNetlinkConfig, error) {
|
|
||||||
conn, err := rtnetlink.Dial(nil)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &RtNetlinkConfig{conn: conn}, nil
|
|
||||||
}
|
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -40,29 +39,17 @@ func (l *LogrusLogger) Writer() io.Writer {
|
|||||||
return l.logger.Writer()
|
return l.logger.Writer()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLogrusLogger(confLevel conf.LogLevel) *LogrusLogger {
|
func NewLogrusLogger() *LogrusLogger {
|
||||||
|
|
||||||
var level logrus.Level
|
|
||||||
|
|
||||||
switch confLevel {
|
|
||||||
case conf.ERROR:
|
|
||||||
level = logrus.ErrorLevel
|
|
||||||
case conf.WARNING:
|
|
||||||
level = logrus.WarnLevel
|
|
||||||
case conf.INFO:
|
|
||||||
level = logrus.InfoLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := logrus.New()
|
logger := logrus.New()
|
||||||
logger.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
|
logger.SetFormatter(&logrus.TextFormatter{FullTimestamp: true})
|
||||||
logger.SetOutput(os.Stdout)
|
logger.SetOutput(os.Stdout)
|
||||||
logger.SetLevel(level)
|
logger.SetLevel(logrus.InfoLevel)
|
||||||
|
|
||||||
return &LogrusLogger{logger: logger}
|
return &LogrusLogger{logger: logger}
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
SetLogger(NewLogrusLogger(conf.INFO))
|
SetLogger(NewLogrusLogger())
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetLogger(l Logger) {
|
func SetLogger(l Logger) {
|
||||||
|
@ -7,23 +7,22 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ip"
|
"github.com/tim-beatham/wgmesh/pkg/ip"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/route"
|
"github.com/tim-beatham/wgmesh/pkg/route"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MeshConfigApplier abstracts applying the mesh configuration
|
// MeshConfigApplyer abstracts applying the mesh configuration
|
||||||
type MeshConfigApplier interface {
|
type MeshConfigApplyer interface {
|
||||||
// ApplyConfig: apply the configurtation
|
|
||||||
ApplyConfig() error
|
ApplyConfig() error
|
||||||
// SetMeshManager: sets the associated manager
|
RemovePeers(meshId string) error
|
||||||
SetMeshManager(manager MeshManager)
|
SetMeshManager(manager MeshManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WgMeshConfigApplier: applies WireGuard configuration
|
// WgMeshConfigApplyer applies WireGuard configuration
|
||||||
type WgMeshConfigApplier struct {
|
type WgMeshConfigApplyer struct {
|
||||||
meshManager MeshManager
|
meshManager MeshManager
|
||||||
routeInstaller route.RouteInstaller
|
routeInstaller route.RouteInstaller
|
||||||
hashFunc func(MeshNode) int
|
hashFunc func(MeshNode) int
|
||||||
@ -36,13 +35,14 @@ type routeNode struct {
|
|||||||
|
|
||||||
type convertMeshNodeParams struct {
|
type convertMeshNodeParams struct {
|
||||||
node MeshNode
|
node MeshNode
|
||||||
|
self MeshNode
|
||||||
mesh MeshProvider
|
mesh MeshProvider
|
||||||
device *wgtypes.Device
|
device *wgtypes.Device
|
||||||
peerToClients map[string][]net.IPNet
|
peerToClients map[string][]net.IPNet
|
||||||
routes map[string][]routeNode
|
routes map[string][]routeNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WgMeshConfigApplier) convertMeshNode(params convertMeshNodeParams) (*wgtypes.PeerConfig, error) {
|
func (m *WgMeshConfigApplyer) convertMeshNode(params convertMeshNodeParams) (*wgtypes.PeerConfig, error) {
|
||||||
pubKey, err := params.node.GetPublicKey()
|
pubKey, err := params.node.GetPublicKey()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -58,7 +58,8 @@ func (m *WgMeshConfigApplier) convertMeshNode(params convertMeshNodeParams) (*wg
|
|||||||
allowedips = append(allowedips, clients...)
|
allowedips = append(allowedips, clients...)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, bestRoutes := range lib.MapValues(params.routes) {
|
for _, route := range params.node.GetRoutes() {
|
||||||
|
bestRoutes := params.routes[route.GetDestination().String()]
|
||||||
var pickedRoute routeNode
|
var pickedRoute routeNode
|
||||||
|
|
||||||
if len(bestRoutes) == 1 {
|
if len(bestRoutes) == 1 {
|
||||||
@ -68,7 +69,8 @@ func (m *WgMeshConfigApplier) convertMeshNode(params convertMeshNodeParams) (*wg
|
|||||||
return lib.HashString(rn.gateway)
|
return lib.HashString(rn.gateway)
|
||||||
}
|
}
|
||||||
|
|
||||||
pickedRoute = lib.ConsistentHash(bestRoutes, params.node, bucketFunc, m.hashFunc)
|
// Else there is more than one candidate so consistently hash
|
||||||
|
pickedRoute = lib.ConsistentHash(bestRoutes, params.self, bucketFunc, m.hashFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pickedRoute.gateway == pubKey.String() {
|
if pickedRoute.gateway == pubKey.String() {
|
||||||
@ -117,13 +119,8 @@ func (m *WgMeshConfigApplier) convertMeshNode(params convertMeshNodeParams) (*wg
|
|||||||
|
|
||||||
// getRoutes: finds the routes with the least hop distance. If more than one route exists
|
// getRoutes: finds the routes with the least hop distance. If more than one route exists
|
||||||
// consistently hash to evenly spread the distribution of traffic
|
// consistently hash to evenly spread the distribution of traffic
|
||||||
func (m *WgMeshConfigApplier) getRoutes(meshProvider MeshProvider) (map[string][]routeNode, error) {
|
func (m *WgMeshConfigApplyer) getRoutes(meshProvider MeshProvider) map[string][]routeNode {
|
||||||
mesh, err := meshProvider.GetMesh()
|
mesh, _ := meshProvider.GetMesh()
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
routes := make(map[string][]routeNode)
|
routes := make(map[string][]routeNode)
|
||||||
|
|
||||||
peers := lib.Filter(lib.MapValues(mesh.GetNodes()), func(p MeshNode) bool {
|
peers := lib.Filter(lib.MapValues(mesh.GetNodes()), func(p MeshNode) bool {
|
||||||
@ -161,18 +158,17 @@ func (m *WgMeshConfigApplier) getRoutes(meshProvider MeshProvider) (map[string][
|
|||||||
// Client's only acessible by another peer
|
// Client's only acessible by another peer
|
||||||
if node.GetType() == conf.CLIENT_ROLE {
|
if node.GetType() == conf.CLIENT_ROLE {
|
||||||
peer := m.getCorrespondingPeer(peers, node)
|
peer := m.getCorrespondingPeer(peers, node)
|
||||||
self, err := meshProvider.GetNode(m.meshManager.GetPublicKey().String())
|
self, _ := m.meshManager.GetSelf(meshProvider.GetMeshId())
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// If the node isn't the self use that peer as the gateway
|
||||||
if !NodeEquals(peer, self) {
|
if !NodeEquals(peer, self) {
|
||||||
peerPub, _ := peer.GetPublicKey()
|
peerPub, _ := peer.GetPublicKey()
|
||||||
rn.gateway = peerPub.String()
|
rn.gateway = peerPub.String()
|
||||||
rn.route = &RouteStub{
|
rn.route = &RouteStub{
|
||||||
Destination: rn.route.GetDestination(),
|
Destination: rn.route.GetDestination(),
|
||||||
Path: append(rn.route.GetPath(), peer.GetWgHost().IP.String()),
|
HopCount: rn.route.GetHopCount() + 1,
|
||||||
|
// Append the path to this peer
|
||||||
|
Path: append(rn.route.GetPath(), peer.GetWgHost().IP.String()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,17 +185,16 @@ func (m *WgMeshConfigApplier) getRoutes(meshProvider MeshProvider) (map[string][
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return routes, nil
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCorrespondignPeer: gets the peer corresponding to the client
|
// getCorrespondignPeer: gets the peer corresponding to the client
|
||||||
func (m *WgMeshConfigApplier) getCorrespondingPeer(peers []MeshNode, client MeshNode) MeshNode {
|
func (m *WgMeshConfigApplyer) getCorrespondingPeer(peers []MeshNode, client MeshNode) MeshNode {
|
||||||
peer := lib.ConsistentHash(peers, client, m.hashFunc, m.hashFunc)
|
peer := lib.ConsistentHash(peers, client, m.hashFunc, m.hashFunc)
|
||||||
return peer
|
return peer
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPeerCfgsToRemove: remove peer configurations that are no longer in the mesh
|
func (m *WgMeshConfigApplyer) getPeerCfgsToRemove(dev *wgtypes.Device, newPeers []wgtypes.PeerConfig) []wgtypes.PeerConfig {
|
||||||
func (m *WgMeshConfigApplier) getPeerCfgsToRemove(dev *wgtypes.Device, newPeers []wgtypes.PeerConfig) []wgtypes.PeerConfig {
|
|
||||||
peers := dev.Peers
|
peers := dev.Peers
|
||||||
peers = lib.Filter(peers, func(p1 wgtypes.Peer) bool {
|
peers = lib.Filter(peers, func(p1 wgtypes.Peer) bool {
|
||||||
return !lib.Contains(newPeers, func(p2 wgtypes.PeerConfig) bool {
|
return !lib.Contains(newPeers, func(p2 wgtypes.PeerConfig) bool {
|
||||||
@ -223,37 +218,27 @@ type GetConfigParams struct {
|
|||||||
routes map[string][]routeNode
|
routes map[string][]routeNode
|
||||||
}
|
}
|
||||||
|
|
||||||
// getClientConfig: if the node is a client get their configuration
|
func (m *WgMeshConfigApplyer) getClientConfig(params *GetConfigParams) (*wgtypes.Config, error) {
|
||||||
func (m *WgMeshConfigApplier) getClientConfig(params *GetConfigParams) (*wgtypes.Config, error) {
|
self, err := m.meshManager.GetSelf(params.mesh.GetMeshId())
|
||||||
ula := &ip.ULABuilder{}
|
ula := &ip.ULABuilder{}
|
||||||
meshNet, _ := ula.GetIPNet(params.mesh.GetMeshId())
|
meshNet, _ := ula.GetIPNet(params.mesh.GetMeshId())
|
||||||
|
|
||||||
routesForMesh := lib.Map(lib.MapValues(params.routes), func(rns []routeNode) []routeNode {
|
routesForMesh := lib.Map(lib.MapValues(params.routes), func(rns []routeNode) []routeNode {
|
||||||
return lib.Filter(rns, func(rn routeNode) bool {
|
return lib.Filter(rns, func(rn routeNode) bool {
|
||||||
node, err := params.mesh.GetNode(rn.gateway)
|
ip, _, _ := net.ParseCIDR(rn.gateway)
|
||||||
return node != nil && err == nil
|
return meshNet.Contains(ip)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
routesForMesh = lib.Filter(routesForMesh, func(rns []routeNode) bool {
|
|
||||||
return len(rns) != 0
|
|
||||||
})
|
|
||||||
|
|
||||||
routes := lib.Map(routesForMesh, func(rs []routeNode) net.IPNet {
|
routes := lib.Map(routesForMesh, func(rs []routeNode) net.IPNet {
|
||||||
return *rs[0].route.GetDestination()
|
return *rs[0].route.GetDestination()
|
||||||
})
|
})
|
||||||
routes = append(routes, *meshNet)
|
routes = append(routes, *meshNet)
|
||||||
|
|
||||||
self, err := params.mesh.GetNode(m.meshManager.GetPublicKey().String())
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(params.peers) == 0 {
|
|
||||||
return nil, fmt.Errorf("no peers in the mesh")
|
|
||||||
}
|
|
||||||
|
|
||||||
peer := m.getCorrespondingPeer(params.peers, self)
|
peer := m.getCorrespondingPeer(params.peers, self)
|
||||||
pubKey, _ := peer.GetPublicKey()
|
pubKey, _ := peer.GetPublicKey()
|
||||||
|
|
||||||
@ -279,38 +264,30 @@ func (m *WgMeshConfigApplier) getClientConfig(params *GetConfigParams) (*wgtypes
|
|||||||
installedRoutes := make([]lib.Route, 0)
|
installedRoutes := make([]lib.Route, 0)
|
||||||
|
|
||||||
for _, route := range peerCfgs[0].AllowedIPs {
|
for _, route := range peerCfgs[0].AllowedIPs {
|
||||||
// Don't install routes that we are directly a part
|
installedRoutes = append(installedRoutes, lib.Route{
|
||||||
// Dont install default route wgctrl handles this for us
|
Gateway: peer.GetWgHost().IP,
|
||||||
if !meshNet.Contains(route.IP) {
|
Destination: route,
|
||||||
installedRoutes = append(installedRoutes, lib.Route{
|
})
|
||||||
Gateway: peer.GetWgHost().IP,
|
|
||||||
Destination: route,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := wgtypes.Config{
|
cfg := wgtypes.Config{
|
||||||
Peers: peerCfgs,
|
Peers: peerCfgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
if params.dev != nil {
|
m.routeInstaller.InstallRoutes(params.dev.Name, installedRoutes...)
|
||||||
m.routeInstaller.InstallRoutes(params.dev.Name, installedRoutes...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cfg, err
|
return &cfg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// getRoutesToInstall: work out if the given node is advertising routes that should be installed into the
|
func (m *WgMeshConfigApplyer) getRoutesToInstall(wgNode *wgtypes.PeerConfig, mesh MeshProvider, node MeshNode) []lib.Route {
|
||||||
// RIB
|
|
||||||
func (m *WgMeshConfigApplier) getRoutesToInstall(wgNode *wgtypes.PeerConfig, mesh MeshProvider, node MeshNode) []lib.Route {
|
|
||||||
routes := make([]lib.Route, 0)
|
routes := make([]lib.Route, 0)
|
||||||
|
|
||||||
for _, route := range wgNode.AllowedIPs {
|
for _, route := range wgNode.AllowedIPs {
|
||||||
ula := &ip.ULABuilder{}
|
ula := &ip.ULABuilder{}
|
||||||
ipNet, _ := ula.GetIPNet(mesh.GetMeshId())
|
ipNet, _ := ula.GetIPNet(mesh.GetMeshId())
|
||||||
|
|
||||||
// Check there is no overlap in network and its not the default route
|
_, defaultRoute, _ := net.ParseCIDR("::/0")
|
||||||
if !ipNet.Contains(route.IP) {
|
|
||||||
|
if !ipNet.Contains(route.IP) && !ipNet.IP.Equal(defaultRoute.IP) {
|
||||||
routes = append(routes, lib.Route{
|
routes = append(routes, lib.Route{
|
||||||
Gateway: node.GetWgHost().IP,
|
Gateway: node.GetWgHost().IP,
|
||||||
Destination: route,
|
Destination: route,
|
||||||
@ -321,12 +298,11 @@ func (m *WgMeshConfigApplier) getRoutesToInstall(wgNode *wgtypes.PeerConfig, mes
|
|||||||
return routes
|
return routes
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPeerConfig: creates the WireGuard configuration for a peer
|
func (m *WgMeshConfigApplyer) getPeerConfig(params *GetConfigParams) (*wgtypes.Config, error) {
|
||||||
func (m *WgMeshConfigApplier) getPeerConfig(params *GetConfigParams) (*wgtypes.Config, error) {
|
|
||||||
peerToClients := make(map[string][]net.IPNet)
|
peerToClients := make(map[string][]net.IPNet)
|
||||||
installedRoutes := make([]lib.Route, 0)
|
installedRoutes := make([]lib.Route, 0)
|
||||||
peerConfigs := make([]wgtypes.PeerConfig, 0)
|
peerConfigs := make([]wgtypes.PeerConfig, 0)
|
||||||
self, err := params.mesh.GetNode(m.meshManager.GetPublicKey().String())
|
self, err := m.meshManager.GetSelf(params.mesh.GetMeshId())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -345,23 +321,23 @@ func (m *WgMeshConfigApplier) getPeerConfig(params *GetConfigParams) (*wgtypes.C
|
|||||||
|
|
||||||
peerToClients[pubKey.String()] = append(clients, *n.GetWgHost())
|
peerToClients[pubKey.String()] = append(clients, *n.GetWgHost())
|
||||||
|
|
||||||
cfg, err := m.convertMeshNode(convertMeshNodeParams{
|
|
||||||
node: n,
|
|
||||||
mesh: params.mesh,
|
|
||||||
device: params.dev,
|
|
||||||
peerToClients: peerToClients,
|
|
||||||
routes: params.routes,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if NodeEquals(self, peer) {
|
if NodeEquals(self, peer) {
|
||||||
|
cfg, err := m.convertMeshNode(convertMeshNodeParams{
|
||||||
|
node: n,
|
||||||
|
self: self,
|
||||||
|
mesh: params.mesh,
|
||||||
|
device: params.dev,
|
||||||
|
peerToClients: peerToClients,
|
||||||
|
routes: params.routes,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
installedRoutes = append(installedRoutes, m.getRoutesToInstall(cfg, params.mesh, n)...)
|
||||||
peerConfigs = append(peerConfigs, *cfg)
|
peerConfigs = append(peerConfigs, *cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
installedRoutes = append(installedRoutes, m.getRoutesToInstall(cfg, params.mesh, n)...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,6 +348,7 @@ func (m *WgMeshConfigApplier) getPeerConfig(params *GetConfigParams) (*wgtypes.C
|
|||||||
|
|
||||||
peer, err := m.convertMeshNode(convertMeshNodeParams{
|
peer, err := m.convertMeshNode(convertMeshNodeParams{
|
||||||
node: n,
|
node: n,
|
||||||
|
self: self,
|
||||||
mesh: params.mesh,
|
mesh: params.mesh,
|
||||||
peerToClients: peerToClients,
|
peerToClients: peerToClients,
|
||||||
routes: params.routes,
|
routes: params.routes,
|
||||||
@ -394,8 +371,7 @@ func (m *WgMeshConfigApplier) getPeerConfig(params *GetConfigParams) (*wgtypes.C
|
|||||||
return &cfg, err
|
return &cfg, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateWgConf: update the WireGuard configuration
|
func (m *WgMeshConfigApplyer) updateWgConf(mesh MeshProvider, routes map[string][]routeNode) error {
|
||||||
func (m *WgMeshConfigApplier) updateWgConf(mesh MeshProvider, routes map[string][]routeNode) error {
|
|
||||||
snap, err := mesh.GetMesh()
|
snap, err := mesh.GetMesh()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -403,11 +379,7 @@ func (m *WgMeshConfigApplier) updateWgConf(mesh MeshProvider, routes map[string]
|
|||||||
}
|
}
|
||||||
|
|
||||||
nodes := lib.MapValues(snap.GetNodes())
|
nodes := lib.MapValues(snap.GetNodes())
|
||||||
dev, err := mesh.GetDevice()
|
dev, _ := mesh.GetDevice()
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
slices.SortFunc(nodes, func(a, b MeshNode) int {
|
slices.SortFunc(nodes, func(a, b MeshNode) int {
|
||||||
return strings.Compare(string(a.GetType()), string(b.GetType()))
|
return strings.Compare(string(a.GetType()), string(b.GetType()))
|
||||||
@ -421,7 +393,7 @@ func (m *WgMeshConfigApplier) updateWgConf(mesh MeshProvider, routes map[string]
|
|||||||
return mn.GetType() == conf.CLIENT_ROLE
|
return mn.GetType() == conf.CLIENT_ROLE
|
||||||
})
|
})
|
||||||
|
|
||||||
self, err := mesh.GetNode(m.meshManager.GetPublicKey().String())
|
self, err := m.meshManager.GetSelf(mesh.GetMeshId())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -460,17 +432,11 @@ func (m *WgMeshConfigApplier) updateWgConf(mesh MeshProvider, routes map[string]
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAllRoutes: works out all the routes to install out of all the routes in the
|
func (m *WgMeshConfigApplyer) getAllRoutes() map[string][]routeNode {
|
||||||
// set of networks the node is a part of
|
|
||||||
func (m *WgMeshConfigApplier) getAllRoutes() (map[string][]routeNode, error) {
|
|
||||||
allRoutes := make(map[string][]routeNode)
|
allRoutes := make(map[string][]routeNode)
|
||||||
|
|
||||||
for _, mesh := range m.meshManager.GetMeshes() {
|
for _, mesh := range m.meshManager.GetMeshes() {
|
||||||
routes, err := m.getRoutes(mesh)
|
routes := m.getRoutes(mesh)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for destination, route := range routes {
|
for destination, route := range routes {
|
||||||
_, ok := allRoutes[destination]
|
_, ok := allRoutes[destination]
|
||||||
@ -488,16 +454,11 @@ func (m *WgMeshConfigApplier) getAllRoutes() (map[string][]routeNode, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allRoutes, nil
|
return allRoutes
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyConfig: apply the WireGuard configuration
|
func (m *WgMeshConfigApplyer) ApplyConfig() error {
|
||||||
func (m *WgMeshConfigApplier) ApplyConfig() error {
|
allRoutes := m.getAllRoutes()
|
||||||
allRoutes, err := m.getAllRoutes()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, mesh := range m.meshManager.GetMeshes() {
|
for _, mesh := range m.meshManager.GetMeshes() {
|
||||||
err := m.updateWgConf(mesh, allRoutes)
|
err := m.updateWgConf(mesh, allRoutes)
|
||||||
@ -510,12 +471,33 @@ func (m *WgMeshConfigApplier) ApplyConfig() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *WgMeshConfigApplier) SetMeshManager(manager MeshManager) {
|
func (m *WgMeshConfigApplyer) RemovePeers(meshId string) error {
|
||||||
|
mesh := m.meshManager.GetMesh(meshId)
|
||||||
|
|
||||||
|
if mesh == nil {
|
||||||
|
return fmt.Errorf("mesh %s does not exist", meshId)
|
||||||
|
}
|
||||||
|
|
||||||
|
dev, err := mesh.GetDevice()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
m.meshManager.GetClient().ConfigureDevice(dev.Name, wgtypes.Config{
|
||||||
|
Peers: make([]wgtypes.PeerConfig, 0),
|
||||||
|
ReplacePeers: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *WgMeshConfigApplyer) SetMeshManager(manager MeshManager) {
|
||||||
m.meshManager = manager
|
m.meshManager = manager
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWgMeshConfigApplier() MeshConfigApplier {
|
func NewWgMeshConfigApplyer() MeshConfigApplyer {
|
||||||
return &WgMeshConfigApplier{
|
return &WgMeshConfigApplyer{
|
||||||
routeInstaller: route.NewRouteInstaller(),
|
routeInstaller: route.NewRouteInstaller(),
|
||||||
hashFunc: func(mn MeshNode) int {
|
hashFunc: func(mn MeshNode) int {
|
||||||
pubKey, _ := mn.GetPublicKey()
|
pubKey, _ := mn.GetPublicKey()
|
||||||
|
@ -3,21 +3,17 @@ package mesh
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/cmd"
|
"github.com/tim-beatham/wgmesh/pkg/cmd"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ip"
|
"github.com/tim-beatham/wgmesh/pkg/ip"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
"github.com/tim-beatham/wgmesh/pkg/wg"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/wg"
|
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MeshManager: abstracts maanging meshes, including installing the WireGuard configuration
|
|
||||||
// to the device, and adding and removing nodes
|
|
||||||
type MeshManager interface {
|
type MeshManager interface {
|
||||||
CreateMesh(params *CreateMeshParams) (string, error)
|
CreateMesh(params *CreateMeshParams) (string, error)
|
||||||
AddMesh(params *AddMeshParams) error
|
AddMesh(params *AddMeshParams) error
|
||||||
@ -28,10 +24,10 @@ type MeshManager interface {
|
|||||||
LeaveMesh(meshId string) error
|
LeaveMesh(meshId string) error
|
||||||
GetSelf(meshId string) (MeshNode, error)
|
GetSelf(meshId string) (MeshNode, error)
|
||||||
ApplyConfig() error
|
ApplyConfig() error
|
||||||
SetDescription(meshId, description string) error
|
SetDescription(description string) error
|
||||||
SetAlias(meshId, alias string) error
|
SetAlias(alias string) error
|
||||||
SetService(meshId, service, value string) error
|
SetService(service string, value string) error
|
||||||
RemoveService(meshId, service string) error
|
RemoveService(service string) error
|
||||||
UpdateTimeStamp() error
|
UpdateTimeStamp() error
|
||||||
GetClient() *wgctrl.Client
|
GetClient() *wgctrl.Client
|
||||||
GetMeshes() map[string]MeshProvider
|
GetMeshes() map[string]MeshProvider
|
||||||
@ -41,15 +37,17 @@ type MeshManager interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type MeshManagerImpl struct {
|
type MeshManagerImpl struct {
|
||||||
meshLock sync.RWMutex
|
lock sync.RWMutex
|
||||||
meshes map[string]MeshProvider
|
Meshes map[string]MeshProvider
|
||||||
RouteManager RouteManager
|
RouteManager RouteManager
|
||||||
Client *wgctrl.Client
|
Client *wgctrl.Client
|
||||||
|
// HostParameters contains information that uniquely locates
|
||||||
|
// the node in the mesh network.
|
||||||
HostParameters *HostParameters
|
HostParameters *HostParameters
|
||||||
conf *conf.DaemonConfiguration
|
conf *conf.DaemonConfiguration
|
||||||
meshProviderFactory MeshProviderFactory
|
meshProviderFactory MeshProviderFactory
|
||||||
nodeFactory MeshNodeFactory
|
nodeFactory MeshNodeFactory
|
||||||
configApplier MeshConfigApplier
|
configApplyer MeshConfigApplyer
|
||||||
idGenerator lib.IdGenerator
|
idGenerator lib.IdGenerator
|
||||||
ipAllocator ip.IPAllocator
|
ipAllocator ip.IPAllocator
|
||||||
interfaceManipulator wg.WgInterfaceManipulator
|
interfaceManipulator wg.WgInterfaceManipulator
|
||||||
@ -57,43 +55,39 @@ type MeshManagerImpl struct {
|
|||||||
OnDelete func(MeshProvider)
|
OnDelete func(MeshProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRouteManager implements MeshManager.
|
||||||
func (m *MeshManagerImpl) GetRouteManager() RouteManager {
|
func (m *MeshManagerImpl) GetRouteManager() RouteManager {
|
||||||
return m.RouteManager
|
return m.RouteManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveService: remove a service from the given mesh.
|
// RemoveService implements MeshManager.
|
||||||
func (m *MeshManagerImpl) RemoveService(meshId, service string) error {
|
func (m *MeshManagerImpl) RemoveService(service string) error {
|
||||||
mesh := m.GetMesh(meshId)
|
for _, mesh := range m.Meshes {
|
||||||
|
err := mesh.RemoveService(m.HostParameters.GetPublicKey(), service)
|
||||||
|
|
||||||
if mesh == nil {
|
if err != nil {
|
||||||
return fmt.Errorf("mesh %s does not exist", meshId)
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !mesh.NodeExists(m.HostParameters.GetPublicKey()) {
|
return nil
|
||||||
return fmt.Errorf("node %s does not exist in the mesh", meshId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mesh.RemoveService(m.HostParameters.GetPublicKey(), service)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetService: add a service to the given mesh
|
// SetService implements MeshManager.
|
||||||
func (m *MeshManagerImpl) SetService(meshId, service, value string) error {
|
func (m *MeshManagerImpl) SetService(service string, value string) error {
|
||||||
mesh := m.GetMesh(meshId)
|
for _, mesh := range m.Meshes {
|
||||||
|
err := mesh.AddService(m.HostParameters.GetPublicKey(), service, value)
|
||||||
|
|
||||||
if mesh == nil {
|
if err != nil {
|
||||||
return fmt.Errorf("mesh %s does not exist", meshId)
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !mesh.NodeExists(m.HostParameters.GetPublicKey()) {
|
return nil
|
||||||
return fmt.Errorf("node %s does not exist in the mesh", meshId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mesh.AddService(m.HostParameters.GetPublicKey(), service, value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNode: gets the node with given id in the mesh network
|
|
||||||
func (m *MeshManagerImpl) GetNode(meshid, nodeId string) MeshNode {
|
func (m *MeshManagerImpl) GetNode(meshid, nodeId string) MeshNode {
|
||||||
mesh, ok := m.meshes[meshid]
|
mesh, ok := m.Meshes[meshid]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
@ -140,10 +134,6 @@ func (m *MeshManagerImpl) CreateMesh(args *CreateMeshParams) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if *meshConfiguration.Role == conf.CLIENT_ROLE {
|
|
||||||
return "", fmt.Errorf("cannot create mesh as a client")
|
|
||||||
}
|
|
||||||
|
|
||||||
meshId, err := m.idGenerator.GetId()
|
meshId, err := m.idGenerator.GetId()
|
||||||
|
|
||||||
var ifName string = ""
|
var ifName string = ""
|
||||||
@ -176,9 +166,9 @@ func (m *MeshManagerImpl) CreateMesh(args *CreateMeshParams) (string, error) {
|
|||||||
return "", fmt.Errorf("error creating mesh: %w", err)
|
return "", fmt.Errorf("error creating mesh: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m.meshLock.Lock()
|
m.lock.Lock()
|
||||||
m.meshes[meshId] = nodeManager
|
m.Meshes[meshId] = nodeManager
|
||||||
m.meshLock.Unlock()
|
m.lock.Unlock()
|
||||||
|
|
||||||
m.cmdRunner.RunCommands(m.conf.BaseConfiguration.PostUp...)
|
m.cmdRunner.RunCommands(m.conf.BaseConfiguration.PostUp...)
|
||||||
|
|
||||||
@ -192,7 +182,7 @@ type AddMeshParams struct {
|
|||||||
Conf *conf.WgConfiguration
|
Conf *conf.WgConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddMesh: Add a new mesh network to the list of addresses
|
// AddMesh: Add the mesh to the list of meshes
|
||||||
func (m *MeshManagerImpl) AddMesh(params *AddMeshParams) error {
|
func (m *MeshManagerImpl) AddMesh(params *AddMeshParams) error {
|
||||||
var ifName string
|
var ifName string
|
||||||
var err error
|
var err error
|
||||||
@ -235,20 +225,20 @@ func (m *MeshManagerImpl) AddMesh(params *AddMeshParams) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
m.meshLock.Lock()
|
m.lock.Lock()
|
||||||
m.meshes[params.MeshId] = meshProvider
|
m.Meshes[params.MeshId] = meshProvider
|
||||||
m.meshLock.Unlock()
|
m.lock.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasChanges: returns true if the mesh has changes
|
// HasChanges returns true if the mesh has changes
|
||||||
func (m *MeshManagerImpl) HasChanges(meshId string) bool {
|
func (m *MeshManagerImpl) HasChanges(meshId string) bool {
|
||||||
return m.meshes[meshId].HasChanges()
|
return m.Meshes[meshId].HasChanges()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMesh: returns the mesh with the given meshid
|
// GetMesh returns the mesh with the given meshid
|
||||||
func (m *MeshManagerImpl) GetMesh(meshId string) MeshProvider {
|
func (m *MeshManagerImpl) GetMesh(meshId string) MeshProvider {
|
||||||
theMesh := m.meshes[meshId]
|
theMesh := m.Meshes[meshId]
|
||||||
return theMesh
|
return theMesh
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,8 +248,6 @@ func (s *MeshManagerImpl) GetPublicKey() *wgtypes.Key {
|
|||||||
return &key
|
return &key
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSelfParams: parameters required to add yourself to a mesh
|
|
||||||
// network
|
|
||||||
type AddSelfParams struct {
|
type AddSelfParams struct {
|
||||||
// MeshId is the ID of the mesh to add this instance to
|
// MeshId is the ID of the mesh to add this instance to
|
||||||
MeshId string
|
MeshId string
|
||||||
@ -269,7 +257,7 @@ type AddSelfParams struct {
|
|||||||
Endpoint string
|
Endpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSelf: adds this host to the mesh
|
// AddSelf adds this host to the mesh
|
||||||
func (s *MeshManagerImpl) AddSelf(params *AddSelfParams) error {
|
func (s *MeshManagerImpl) AddSelf(params *AddSelfParams) error {
|
||||||
mesh := s.GetMesh(params.MeshId)
|
mesh := s.GetMesh(params.MeshId)
|
||||||
|
|
||||||
@ -289,36 +277,10 @@ func (s *MeshManagerImpl) AddSelf(params *AddSelfParams) error {
|
|||||||
|
|
||||||
pubKey := s.HostParameters.PrivateKey.PublicKey()
|
pubKey := s.HostParameters.PrivateKey.PublicKey()
|
||||||
|
|
||||||
collisionCount := uint8(0)
|
nodeIP, err := s.ipAllocator.GetIP(pubKey, params.MeshId)
|
||||||
|
|
||||||
var nodeIP net.IP
|
if err != nil {
|
||||||
|
return err
|
||||||
// Perform Duplicate Address Detection with the nodes
|
|
||||||
// that are already in the network
|
|
||||||
for {
|
|
||||||
generatedIP, err := s.ipAllocator.GetIP(pubKey, params.MeshId, collisionCount)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
snapshot, err := mesh.GetMesh()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
proposition := func(node MeshNode) bool {
|
|
||||||
ipNet := node.GetWgHost()
|
|
||||||
return ipNet.IP.Equal(nodeIP)
|
|
||||||
}
|
|
||||||
|
|
||||||
if lib.Contains(lib.MapValues(snapshot.GetNodes()), proposition) {
|
|
||||||
collisionCount++
|
|
||||||
} else {
|
|
||||||
nodeIP = generatedIP
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node := s.nodeFactory.Build(&MeshNodeFactoryParams{
|
node := s.nodeFactory.Build(&MeshNodeFactoryParams{
|
||||||
@ -343,11 +305,11 @@ func (s *MeshManagerImpl) AddSelf(params *AddSelfParams) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.meshes[params.MeshId].AddNode(node)
|
s.Meshes[params.MeshId].AddNode(node)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeaveMesh: leaves the mesh network and force a synchronsiation
|
// LeaveMesh leaves the mesh network
|
||||||
func (s *MeshManagerImpl) LeaveMesh(meshId string) error {
|
func (s *MeshManagerImpl) LeaveMesh(meshId string) error {
|
||||||
mesh := s.GetMesh(meshId)
|
mesh := s.GetMesh(meshId)
|
||||||
|
|
||||||
@ -358,16 +320,16 @@ func (s *MeshManagerImpl) LeaveMesh(meshId string) error {
|
|||||||
err := mesh.RemoveNode(s.HostParameters.GetPublicKey())
|
err := mesh.RemoveNode(s.HostParameters.GetPublicKey())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log.WriteErrorf(err.Error())
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.OnDelete != nil {
|
if s.OnDelete != nil {
|
||||||
s.OnDelete(mesh)
|
s.OnDelete(mesh)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.meshLock.Lock()
|
s.lock.Lock()
|
||||||
delete(s.meshes, meshId)
|
delete(s.Meshes, meshId)
|
||||||
s.meshLock.Unlock()
|
s.lock.Unlock()
|
||||||
|
|
||||||
s.cmdRunner.RunCommands(s.conf.BaseConfiguration.PreDown...)
|
s.cmdRunner.RunCommands(s.conf.BaseConfiguration.PreDown...)
|
||||||
|
|
||||||
@ -386,11 +348,12 @@ func (s *MeshManagerImpl) LeaveMesh(meshId string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s.cmdRunner.RunCommands(s.conf.BaseConfiguration.PostDown...)
|
s.cmdRunner.RunCommands(s.conf.BaseConfiguration.PostDown...)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MeshManagerImpl) GetSelf(meshId string) (MeshNode, error) {
|
func (s *MeshManagerImpl) GetSelf(meshId string) (MeshNode, error) {
|
||||||
meshInstance, ok := s.meshes[meshId]
|
meshInstance, ok := s.Meshes[meshId]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("mesh %s does not exist", meshId)
|
return nil, fmt.Errorf("mesh %s does not exist", meshId)
|
||||||
@ -405,46 +368,51 @@ func (s *MeshManagerImpl) GetSelf(meshId string) (MeshNode, error) {
|
|||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyConfig: applies the WireGuard configuration
|
|
||||||
// adds routes to the RIB and so forth.
|
|
||||||
func (s *MeshManagerImpl) ApplyConfig() error {
|
func (s *MeshManagerImpl) ApplyConfig() error {
|
||||||
if s.conf.StubWg {
|
if s.conf.StubWg {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return s.configApplier.ApplyConfig()
|
|
||||||
|
err := s.configApplyer.ApplyConfig()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *MeshManagerImpl) SetDescription(meshId, description string) error {
|
func (s *MeshManagerImpl) SetDescription(description string) error {
|
||||||
mesh := s.GetMesh(meshId)
|
meshes := s.GetMeshes()
|
||||||
|
for _, mesh := range meshes {
|
||||||
|
if mesh.NodeExists(s.HostParameters.GetPublicKey()) {
|
||||||
|
err := mesh.SetDescription(s.HostParameters.GetPublicKey(), description)
|
||||||
|
|
||||||
if mesh == nil {
|
if err != nil {
|
||||||
return fmt.Errorf("mesh %s does not exist", meshId)
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !mesh.NodeExists(s.HostParameters.GetPublicKey()) {
|
return nil
|
||||||
return fmt.Errorf("node %s does not exist in the mesh", meshId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mesh.SetDescription(s.HostParameters.GetPublicKey(), description)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAlias sets the alias of the node for the given meshid
|
// SetAlias implements MeshManager.
|
||||||
func (s *MeshManagerImpl) SetAlias(meshId, alias string) error {
|
func (s *MeshManagerImpl) SetAlias(alias string) error {
|
||||||
mesh := s.GetMesh(meshId)
|
meshes := s.GetMeshes()
|
||||||
|
for _, mesh := range meshes {
|
||||||
|
if mesh.NodeExists(s.HostParameters.GetPublicKey()) {
|
||||||
|
err := mesh.SetAlias(s.HostParameters.GetPublicKey(), alias)
|
||||||
|
|
||||||
if mesh == nil {
|
if err != nil {
|
||||||
return fmt.Errorf("mesh %s does not exist", meshId)
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
if !mesh.NodeExists(s.HostParameters.GetPublicKey()) {
|
|
||||||
return fmt.Errorf("node %s does not exist in the mesh", meshId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return mesh.SetAlias(s.HostParameters.GetPublicKey(), alias)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateTimeStamp: updates the timestamp of this node in all meshes
|
// UpdateTimeStamp updates the timestamp of this node in all meshes
|
||||||
// essentially performs heartbeat if the node is the leader
|
|
||||||
func (s *MeshManagerImpl) UpdateTimeStamp() error {
|
func (s *MeshManagerImpl) UpdateTimeStamp() error {
|
||||||
meshes := s.GetMeshes()
|
meshes := s.GetMeshes()
|
||||||
for _, mesh := range meshes {
|
for _, mesh := range meshes {
|
||||||
@ -464,30 +432,26 @@ func (s *MeshManagerImpl) GetClient() *wgctrl.Client {
|
|||||||
return s.Client
|
return s.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMeshes: get all meshes the node is part of
|
|
||||||
func (s *MeshManagerImpl) GetMeshes() map[string]MeshProvider {
|
func (s *MeshManagerImpl) GetMeshes() map[string]MeshProvider {
|
||||||
meshes := make(map[string]MeshProvider)
|
meshes := make(map[string]MeshProvider)
|
||||||
|
|
||||||
// GetMesh: copies the map of meshes to a new map
|
s.lock.RLock()
|
||||||
// to prevent a whole range of concurrency issues
|
|
||||||
// due to iteration and modification
|
|
||||||
s.meshLock.RLock()
|
|
||||||
|
|
||||||
for id, mesh := range s.meshes {
|
for id, mesh := range s.Meshes {
|
||||||
meshes[id] = mesh
|
meshes[id] = mesh
|
||||||
}
|
}
|
||||||
|
|
||||||
s.meshLock.RUnlock()
|
s.lock.RUnlock()
|
||||||
return meshes
|
return meshes
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close: close the mesh manager
|
// Close the mesh manager
|
||||||
func (s *MeshManagerImpl) Close() error {
|
func (s *MeshManagerImpl) Close() error {
|
||||||
if s.conf.StubWg {
|
if s.conf.StubWg {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, mesh := range s.meshes {
|
for _, mesh := range s.Meshes {
|
||||||
dev, err := mesh.GetDevice()
|
dev, err := mesh.GetDevice()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -504,7 +468,7 @@ func (s *MeshManagerImpl) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMeshManagerParams: params required to create an instance of a mesh manager
|
// NewMeshManagerParams params required to create an instance of a mesh manager
|
||||||
type NewMeshManagerParams struct {
|
type NewMeshManagerParams struct {
|
||||||
Conf conf.DaemonConfiguration
|
Conf conf.DaemonConfiguration
|
||||||
Client *wgctrl.Client
|
Client *wgctrl.Client
|
||||||
@ -513,13 +477,13 @@ type NewMeshManagerParams struct {
|
|||||||
IdGenerator lib.IdGenerator
|
IdGenerator lib.IdGenerator
|
||||||
IPAllocator ip.IPAllocator
|
IPAllocator ip.IPAllocator
|
||||||
InterfaceManipulator wg.WgInterfaceManipulator
|
InterfaceManipulator wg.WgInterfaceManipulator
|
||||||
ConfigApplier MeshConfigApplier
|
ConfigApplyer MeshConfigApplyer
|
||||||
RouteManager RouteManager
|
RouteManager RouteManager
|
||||||
CommandRunner cmd.CmdRunner
|
CommandRunner cmd.CmdRunner
|
||||||
OnDelete func(MeshProvider)
|
OnDelete func(MeshProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMeshManager: Creates a new instance of a mesh manager with the given parameters
|
// Creates a new instance of a mesh manager with the given parameters
|
||||||
func NewMeshManager(params *NewMeshManagerParams) MeshManager {
|
func NewMeshManager(params *NewMeshManagerParams) MeshManager {
|
||||||
privateKey, _ := wgtypes.GeneratePrivateKey()
|
privateKey, _ := wgtypes.GeneratePrivateKey()
|
||||||
hostParams := HostParameters{
|
hostParams := HostParameters{
|
||||||
@ -527,7 +491,7 @@ func NewMeshManager(params *NewMeshManagerParams) MeshManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m := &MeshManagerImpl{
|
m := &MeshManagerImpl{
|
||||||
meshes: make(map[string]MeshProvider),
|
Meshes: make(map[string]MeshProvider),
|
||||||
HostParameters: &hostParams,
|
HostParameters: &hostParams,
|
||||||
meshProviderFactory: params.MeshProvider,
|
meshProviderFactory: params.MeshProvider,
|
||||||
nodeFactory: params.NodeFactory,
|
nodeFactory: params.NodeFactory,
|
||||||
@ -535,7 +499,7 @@ func NewMeshManager(params *NewMeshManagerParams) MeshManager {
|
|||||||
conf: ¶ms.Conf,
|
conf: ¶ms.Conf,
|
||||||
}
|
}
|
||||||
|
|
||||||
m.configApplier = params.ConfigApplier
|
m.configApplyer = params.ConfigApplyer
|
||||||
m.RouteManager = params.RouteManager
|
m.RouteManager = params.RouteManager
|
||||||
|
|
||||||
if m.RouteManager == nil {
|
if m.RouteManager == nil {
|
||||||
|
@ -3,10 +3,10 @@ package mesh
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ip"
|
"github.com/tim-beatham/wgmesh/pkg/ip"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/wg"
|
"github.com/tim-beatham/wgmesh/pkg/wg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getMeshConfiguration() *conf.DaemonConfiguration {
|
func getMeshConfiguration() *conf.DaemonConfiguration {
|
||||||
@ -22,12 +22,13 @@ func getMeshConfiguration() *conf.DaemonConfiguration {
|
|||||||
CaCertificatePath: "./somecacertificatepath",
|
CaCertificatePath: "./somecacertificatepath",
|
||||||
SkipCertVerification: true,
|
SkipCertVerification: true,
|
||||||
Timeout: 5,
|
Timeout: 5,
|
||||||
|
Profile: false,
|
||||||
StubWg: true,
|
StubWg: true,
|
||||||
SyncInterval: 2,
|
SyncRate: 2,
|
||||||
Heartbeat: 60,
|
KeepAliveTime: 60,
|
||||||
ClusterSize: 64,
|
ClusterSize: 64,
|
||||||
InterClusterChance: 0.15,
|
InterClusterChance: 0.15,
|
||||||
Branch: 3,
|
BranchRate: 3,
|
||||||
InfectionCount: 3,
|
InfectionCount: 3,
|
||||||
BaseConfiguration: conf.WgConfiguration{
|
BaseConfiguration: conf.WgConfiguration{
|
||||||
IPDiscovery: &ipDiscovery,
|
IPDiscovery: &ipDiscovery,
|
||||||
@ -47,7 +48,7 @@ func getMeshManager() MeshManager {
|
|||||||
IdGenerator: &lib.UUIDGenerator{},
|
IdGenerator: &lib.UUIDGenerator{},
|
||||||
IPAllocator: &ip.ULABuilder{},
|
IPAllocator: &ip.ULABuilder{},
|
||||||
InterfaceManipulator: &wg.WgInterfaceManipulatorStub{},
|
InterfaceManipulator: &wg.WgInterfaceManipulatorStub{},
|
||||||
ConfigApplier: &MeshConfigApplierStub{},
|
ConfigApplyer: &MeshConfigApplyerStub{},
|
||||||
RouteManager: &RouteManagerStub{},
|
RouteManager: &RouteManagerStub{},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -212,7 +213,7 @@ func TestLeaveMeshDeletesMesh(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetAliasUpdatesAliasOfNode(t *testing.T) {
|
func TestSetAlias(t *testing.T) {
|
||||||
manager := getMeshManager()
|
manager := getMeshManager()
|
||||||
alias := "Firpo"
|
alias := "Firpo"
|
||||||
|
|
||||||
@ -220,13 +221,14 @@ func TestSetAliasUpdatesAliasOfNode(t *testing.T) {
|
|||||||
Port: 5000,
|
Port: 5000,
|
||||||
Conf: &conf.WgConfiguration{},
|
Conf: &conf.WgConfiguration{},
|
||||||
})
|
})
|
||||||
|
|
||||||
manager.AddSelf(&AddSelfParams{
|
manager.AddSelf(&AddSelfParams{
|
||||||
MeshId: meshId,
|
MeshId: meshId,
|
||||||
WgPort: 5000,
|
WgPort: 5000,
|
||||||
Endpoint: "abc.com:8080",
|
Endpoint: "abc.com:8080",
|
||||||
})
|
})
|
||||||
|
|
||||||
err := manager.SetAlias(meshId, alias)
|
err := manager.SetAlias(alias)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`failed to set the alias`)
|
t.Fatalf(`failed to set the alias`)
|
||||||
@ -243,7 +245,7 @@ func TestSetAliasUpdatesAliasOfNode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetDescriptionSetsTheDescriptionOfTheNode(t *testing.T) {
|
func TestSetDescription(t *testing.T) {
|
||||||
manager := getMeshManager()
|
manager := getMeshManager()
|
||||||
description := "wooooo"
|
description := "wooooo"
|
||||||
|
|
||||||
@ -252,13 +254,23 @@ func TestSetDescriptionSetsTheDescriptionOfTheNode(t *testing.T) {
|
|||||||
Conf: &conf.WgConfiguration{},
|
Conf: &conf.WgConfiguration{},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
meshId2, _ := manager.CreateMesh(&CreateMeshParams{
|
||||||
|
Port: 5001,
|
||||||
|
Conf: &conf.WgConfiguration{},
|
||||||
|
})
|
||||||
|
|
||||||
manager.AddSelf(&AddSelfParams{
|
manager.AddSelf(&AddSelfParams{
|
||||||
MeshId: meshId1,
|
MeshId: meshId1,
|
||||||
WgPort: 5000,
|
WgPort: 5000,
|
||||||
Endpoint: "abc.com:8080",
|
Endpoint: "abc.com:8080",
|
||||||
})
|
})
|
||||||
|
manager.AddSelf(&AddSelfParams{
|
||||||
|
MeshId: meshId2,
|
||||||
|
WgPort: 5000,
|
||||||
|
Endpoint: "abc.com:8080",
|
||||||
|
})
|
||||||
|
|
||||||
err := manager.SetDescription(meshId1, description)
|
err := manager.SetDescription(description)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf(`failed to set the descriptions`)
|
t.Fatalf(`failed to set the descriptions`)
|
||||||
@ -273,7 +285,18 @@ func TestSetDescriptionSetsTheDescriptionOfTheNode(t *testing.T) {
|
|||||||
if description != self1.GetDescription() {
|
if description != self1.GetDescription() {
|
||||||
t.Fatalf(`description should be %s was %s`, description, self1.GetDescription())
|
t.Fatalf(`description should be %s was %s`, description, self1.GetDescription())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self2, err := manager.GetSelf(meshId2)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`failed to set the description`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if description != self2.GetDescription() {
|
||||||
|
t.Fatalf(`description should be %s was %s`, description, self2.GetDescription())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUpdateTimeStampUpdatesAllMeshes(t *testing.T) {
|
func TestUpdateTimeStampUpdatesAllMeshes(t *testing.T) {
|
||||||
manager := getMeshManager()
|
manager := getMeshManager()
|
||||||
|
|
||||||
@ -304,68 +327,3 @@ func TestUpdateTimeStampUpdatesAllMeshes(t *testing.T) {
|
|||||||
t.Fatalf(`failed to update the timestamp`)
|
t.Fatalf(`failed to update the timestamp`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddServiceAddsServiceToTheMesh(t *testing.T) {
|
|
||||||
manager := getMeshManager()
|
|
||||||
|
|
||||||
meshId1, _ := manager.CreateMesh(&CreateMeshParams{
|
|
||||||
Port: 5000,
|
|
||||||
Conf: &conf.WgConfiguration{},
|
|
||||||
})
|
|
||||||
manager.AddSelf(&AddSelfParams{
|
|
||||||
MeshId: meshId1,
|
|
||||||
WgPort: 5000,
|
|
||||||
Endpoint: "abc.com:8080",
|
|
||||||
})
|
|
||||||
|
|
||||||
serviceName := "hello"
|
|
||||||
manager.SetService(meshId1, serviceName, "dave")
|
|
||||||
|
|
||||||
self, err := manager.GetSelf(meshId1)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf(`error thrown %s:`, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := self.GetServices()[serviceName]; !ok {
|
|
||||||
t.Fatalf(`service not added`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRemoveServiceRemovesTheServiceFromTheMesh(t *testing.T) {
|
|
||||||
manager := getMeshManager()
|
|
||||||
|
|
||||||
meshId1, _ := manager.CreateMesh(&CreateMeshParams{
|
|
||||||
Port: 5000,
|
|
||||||
Conf: &conf.WgConfiguration{},
|
|
||||||
})
|
|
||||||
manager.AddSelf(&AddSelfParams{
|
|
||||||
MeshId: meshId1,
|
|
||||||
WgPort: 5000,
|
|
||||||
Endpoint: "abc.com:8080",
|
|
||||||
})
|
|
||||||
|
|
||||||
serviceName := "hello"
|
|
||||||
manager.SetService(meshId1, serviceName, "dave")
|
|
||||||
|
|
||||||
self, err := manager.GetSelf(meshId1)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf(`error thrown %s:`, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := self.GetServices()[serviceName]; !ok {
|
|
||||||
t.Fatalf(`service not added`)
|
|
||||||
}
|
|
||||||
|
|
||||||
manager.RemoveService(meshId1, serviceName)
|
|
||||||
self, err = manager.GetSelf(meshId1)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf(`error thrown %s:`, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, ok := self.GetServices()[serviceName]; ok {
|
|
||||||
t.Fatalf(`service still exists`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,13 +3,11 @@ package mesh
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ip"
|
"github.com/tim-beatham/wgmesh/pkg/ip"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RouteManager: manager that leaks routes between meshes
|
|
||||||
type RouteManager interface {
|
type RouteManager interface {
|
||||||
// UpdateRoutes: leak all routes in each mesh
|
|
||||||
UpdateRoutes() error
|
UpdateRoutes() error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,17 +19,12 @@ func (r *RouteManagerImpl) UpdateRoutes() error {
|
|||||||
meshes := r.meshManager.GetMeshes()
|
meshes := r.meshManager.GetMeshes()
|
||||||
routes := make(map[string][]Route)
|
routes := make(map[string][]Route)
|
||||||
|
|
||||||
for _, mesh := range meshes {
|
|
||||||
// Make empty routes so that routes are retracted
|
|
||||||
routes[mesh.GetMeshId()] = make([]Route, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, mesh1 := range meshes {
|
for _, mesh1 := range meshes {
|
||||||
if !*mesh1.GetConfiguration().AdvertiseRoutes {
|
if !*mesh1.GetConfiguration().AdvertiseRoutes {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
self, err := mesh1.GetNode(r.meshManager.GetPublicKey().String())
|
self, err := r.meshManager.GetSelf(mesh1.GetMeshId())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -46,6 +39,7 @@ func (r *RouteManagerImpl) UpdateRoutes() error {
|
|||||||
|
|
||||||
defaultRoute := &RouteStub{
|
defaultRoute := &RouteStub{
|
||||||
Destination: ipv6Default,
|
Destination: ipv6Default,
|
||||||
|
HopCount: 0,
|
||||||
Path: []string{mesh1.GetMeshId()},
|
Path: []string{mesh1.GetMeshId()},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,6 +68,7 @@ func (r *RouteManagerImpl) UpdateRoutes() error {
|
|||||||
|
|
||||||
routeValues = append(routeValues, &RouteStub{
|
routeValues = append(routeValues, &RouteStub{
|
||||||
Destination: mesh1IpNet,
|
Destination: mesh1IpNet,
|
||||||
|
HopCount: 0,
|
||||||
Path: []string{mesh1.GetMeshId()},
|
Path: []string{mesh1.GetMeshId()},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -95,21 +90,15 @@ func (r *RouteManagerImpl) UpdateRoutes() error {
|
|||||||
|
|
||||||
// Calculate the set different of each, working out routes to remove and to keep.
|
// Calculate the set different of each, working out routes to remove and to keep.
|
||||||
for meshId, meshRoutes := range routes {
|
for meshId, meshRoutes := range routes {
|
||||||
mesh := meshes[meshId]
|
mesh := r.meshManager.GetMesh(meshId)
|
||||||
|
self, _ := r.meshManager.GetSelf(meshId)
|
||||||
self, err := mesh.GetNode(r.meshManager.GetPublicKey().String())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
toRemove := make([]Route, 0)
|
toRemove := make([]Route, 0)
|
||||||
|
|
||||||
prevRoutes := self.GetRoutes()
|
prevRoutes, _ := mesh.GetRoutes(NodeID(self))
|
||||||
|
|
||||||
for _, route := range prevRoutes {
|
for _, route := range prevRoutes {
|
||||||
if !lib.Contains(meshRoutes, func(r Route) bool {
|
if !lib.Contains(meshRoutes, func(r Route) bool {
|
||||||
return RouteEqual(r, route)
|
return RouteEquals(r, route)
|
||||||
}) {
|
}) {
|
||||||
toRemove = append(toRemove, route)
|
toRemove = append(toRemove, route)
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
@ -30,8 +30,8 @@ func (*MeshNodeStub) GetType() conf.NodeType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetServices implements MeshNode.
|
// GetServices implements MeshNode.
|
||||||
func (m *MeshNodeStub) GetServices() map[string]string {
|
func (*MeshNodeStub) GetServices() map[string]string {
|
||||||
return m.services
|
return make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAlias implements MeshNode.
|
// GetAlias implements MeshNode.
|
||||||
@ -249,21 +249,20 @@ func (s *StubNodeFactory) Build(params *MeshNodeFactoryParams) MeshNode {
|
|||||||
routes: make([]Route, 0),
|
routes: make([]Route, 0),
|
||||||
identifier: "abc",
|
identifier: "abc",
|
||||||
description: "A Mesh Node Stub",
|
description: "A Mesh Node Stub",
|
||||||
services: make(map[string]string),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MeshConfigApplierStub struct{}
|
type MeshConfigApplyerStub struct{}
|
||||||
|
|
||||||
func (a *MeshConfigApplierStub) ApplyConfig() error {
|
func (a *MeshConfigApplyerStub) ApplyConfig() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *MeshConfigApplierStub) RemovePeers(meshId string) error {
|
func (a *MeshConfigApplyerStub) RemovePeers(meshId string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *MeshConfigApplierStub) SetMeshManager(manager MeshManager) {
|
func (a *MeshConfigApplyerStub) SetMeshManager(manager MeshManager) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type MeshManagerStub struct {
|
type MeshManagerStub struct {
|
||||||
@ -272,32 +271,32 @@ type MeshManagerStub struct {
|
|||||||
|
|
||||||
// GetRouteManager implements MeshManager.
|
// GetRouteManager implements MeshManager.
|
||||||
func (*MeshManagerStub) GetRouteManager() RouteManager {
|
func (*MeshManagerStub) GetRouteManager() RouteManager {
|
||||||
return nil
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNode implements MeshManager.
|
// GetNode implements MeshManager.
|
||||||
func (*MeshManagerStub) GetNode(meshId, nodeId string) MeshNode {
|
func (*MeshManagerStub) GetNode(string, string) MeshNode {
|
||||||
return nil
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveService implements MeshManager.
|
// RemoveService implements MeshManager.
|
||||||
func (*MeshManagerStub) RemoveService(meshId, service string) error {
|
func (*MeshManagerStub) RemoveService(service string) error {
|
||||||
return nil
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetService implements MeshManager.
|
// SetService implements MeshManager.
|
||||||
func (*MeshManagerStub) SetService(meshId, service, value string) error {
|
func (*MeshManagerStub) SetService(service string, value string) error {
|
||||||
return nil
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetAlias implements MeshManager.
|
// SetAlias implements MeshManager.
|
||||||
func (*MeshManagerStub) SetAlias(meshId, alias string) error {
|
func (*MeshManagerStub) SetAlias(alias string) error {
|
||||||
return nil
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements MeshManager.
|
// Close implements MeshManager.
|
||||||
func (*MeshManagerStub) Close() error {
|
func (*MeshManagerStub) Close() error {
|
||||||
return nil
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prune implements MeshManager.
|
// Prune implements MeshManager.
|
||||||
@ -349,7 +348,7 @@ func (m *MeshManagerStub) ApplyConfig() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MeshManagerStub) SetDescription(meshId, description string) error {
|
func (m *MeshManagerStub) SetDescription(description string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
@ -21,6 +21,12 @@ type Route interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RouteEqual(r1 Route, r2 Route) bool {
|
func RouteEqual(r1 Route, r2 Route) bool {
|
||||||
|
return r1.GetDestination().IP.Equal(r2.GetDestination().IP) &&
|
||||||
|
r1.GetHopCount() == r2.GetHopCount() &&
|
||||||
|
slices.Equal(r1.GetPath(), r2.GetPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func RouteEquals(r1, r2 Route) bool {
|
||||||
return r1.GetDestination().String() == r2.GetDestination().String() &&
|
return r1.GetDestination().String() == r2.GetDestination().String() &&
|
||||||
r1.GetHopCount() == r2.GetHopCount() &&
|
r1.GetHopCount() == r2.GetHopCount() &&
|
||||||
slices.Equal(r1.GetPath(), r2.GetPath())
|
slices.Equal(r1.GetPath(), r2.GetPath())
|
||||||
@ -28,6 +34,7 @@ func RouteEqual(r1 Route, r2 Route) bool {
|
|||||||
|
|
||||||
type RouteStub struct {
|
type RouteStub struct {
|
||||||
Destination *net.IPNet
|
Destination *net.IPNet
|
||||||
|
HopCount int
|
||||||
Path []string
|
Path []string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +43,7 @@ func (r *RouteStub) GetDestination() *net.IPNet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RouteStub) GetHopCount() int {
|
func (r *RouteStub) GetHopCount() int {
|
||||||
return len(r.Path)
|
return r.HopCount
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RouteStub) GetPath() []string {
|
func (r *RouteStub) GetPath() []string {
|
||||||
@ -74,10 +81,6 @@ func NodeEquals(node1, node2 MeshNode) bool {
|
|||||||
key1, _ := node1.GetPublicKey()
|
key1, _ := node1.GetPublicKey()
|
||||||
key2, _ := node2.GetPublicKey()
|
key2, _ := node2.GetPublicKey()
|
||||||
|
|
||||||
if node1 == nil || node2 == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return key1.String() == key2.String()
|
return key1.String() == key2.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jmespath/go-jmespath"
|
"github.com/jmespath/go-jmespath"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Querier queries a data store for the given data
|
// Querier queries a data store for the given data
|
||||||
@ -17,24 +17,20 @@ type Querier interface {
|
|||||||
Query(meshId string, queryParams string) ([]byte, error)
|
Query(meshId string, queryParams string) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JmesQuerier: queries the datstore in JMESPath syntax
|
|
||||||
type JmesQuerier struct {
|
type JmesQuerier struct {
|
||||||
manager mesh.MeshManager
|
manager mesh.MeshManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryError: query error if something went wrong
|
|
||||||
type QueryError struct {
|
type QueryError struct {
|
||||||
msg string
|
msg string
|
||||||
}
|
}
|
||||||
|
|
||||||
// QuerRoute: represents a route in the query
|
|
||||||
type QueryRoute struct {
|
type QueryRoute struct {
|
||||||
Destination string `json:"destination"`
|
Destination string `json:"destination"`
|
||||||
HopCount int `json:"hopCount"`
|
HopCount int `json:"hopCount"`
|
||||||
Path string `json:"path"`
|
Path string `json:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryNode: represents a single node in the query
|
|
||||||
type QueryNode struct {
|
type QueryNode struct {
|
||||||
HostEndpoint string `json:"hostEndpoint"`
|
HostEndpoint string `json:"hostEndpoint"`
|
||||||
PublicKey string `json:"publicKey"`
|
PublicKey string `json:"publicKey"`
|
||||||
@ -52,7 +48,7 @@ func (m *QueryError) Error() string {
|
|||||||
return m.msg
|
return m.msg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query: queries the the datastore at the given meshid
|
// Query: queries the data
|
||||||
func (j *JmesQuerier) Query(meshId, queryParams string) ([]byte, error) {
|
func (j *JmesQuerier) Query(meshId, queryParams string) ([]byte, error) {
|
||||||
mesh, ok := j.manager.GetMeshes()[meshId]
|
mesh, ok := j.manager.GetMeshes()[meshId]
|
||||||
|
|
||||||
@ -78,7 +74,6 @@ func (j *JmesQuerier) Query(meshId, queryParams string) ([]byte, error) {
|
|||||||
return bytes, err
|
return bytes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MeshNodeToQuerynode: convert the mesh node into a query abstraction
|
|
||||||
func MeshNodeToQueryNode(node mesh.MeshNode) *QueryNode {
|
func MeshNodeToQueryNode(node mesh.MeshNode) *QueryNode {
|
||||||
queryNode := new(QueryNode)
|
queryNode := new(QueryNode)
|
||||||
queryNode.HostEndpoint = node.GetHostEndpoint()
|
queryNode.HostEndpoint = node.GetHostEndpoint()
|
||||||
|
@ -4,22 +4,20 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ipc"
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/rpc"
|
"github.com/tim-beatham/wgmesh/pkg/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IpcHandler: represents a handler for ipc calls
|
|
||||||
type IpcHandler struct {
|
type IpcHandler struct {
|
||||||
Server ctrlserver.CtrlServer
|
Server ctrlserver.CtrlServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// getOverrideConfiguration: override any specific WireGuard configuration
|
|
||||||
func getOverrideConfiguration(args *ipc.WireGuardArgs) conf.WgConfiguration {
|
func getOverrideConfiguration(args *ipc.WireGuardArgs) conf.WgConfiguration {
|
||||||
overrideConf := conf.WgConfiguration{}
|
overrideConf := conf.WgConfiguration{}
|
||||||
|
|
||||||
@ -42,17 +40,20 @@ func getOverrideConfiguration(args *ipc.WireGuardArgs) conf.WgConfiguration {
|
|||||||
return overrideConf
|
return overrideConf
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateMesh: create a new mesh network
|
|
||||||
func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
||||||
overrideConf := getOverrideConfiguration(&args.WgArgs)
|
overrideConf := getOverrideConfiguration(&args.WgArgs)
|
||||||
|
|
||||||
|
if overrideConf.Role != nil && *overrideConf.Role == conf.CLIENT_ROLE {
|
||||||
|
return fmt.Errorf("cannot create a mesh with no public endpoint")
|
||||||
|
}
|
||||||
|
|
||||||
meshId, err := n.Server.GetMeshManager().CreateMesh(&mesh.CreateMeshParams{
|
meshId, err := n.Server.GetMeshManager().CreateMesh(&mesh.CreateMeshParams{
|
||||||
Port: args.WgArgs.WgPort,
|
Port: args.WgArgs.WgPort,
|
||||||
Conf: &overrideConf,
|
Conf: &overrideConf,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("could not create mesh")
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = n.Server.GetMeshManager().AddSelf(&mesh.AddSelfParams{
|
err = n.Server.GetMeshManager().AddSelf(&mesh.AddSelfParams{
|
||||||
@ -62,14 +63,13 @@ func (n *IpcHandler) CreateMesh(args *ipc.NewMeshArgs, reply *string) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("could not create mesh: " + err.Error())
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*reply = meshId
|
*reply = meshId
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMeshes: list mesh networks
|
|
||||||
func (n *IpcHandler) ListMeshes(_ string, reply *ipc.ListMeshReply) error {
|
func (n *IpcHandler) ListMeshes(_ string, reply *ipc.ListMeshReply) error {
|
||||||
meshNames := make([]string, len(n.Server.GetMeshManager().GetMeshes()))
|
meshNames := make([]string, len(n.Server.GetMeshManager().GetMeshes()))
|
||||||
|
|
||||||
@ -79,35 +79,29 @@ func (n *IpcHandler) ListMeshes(_ string, reply *ipc.ListMeshReply) error {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
slices.Sort(meshNames)
|
|
||||||
*reply = ipc.ListMeshReply{Meshes: meshNames}
|
*reply = ipc.ListMeshReply{Meshes: meshNames}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinMesh: join a mesh network
|
func (n *IpcHandler) JoinMesh(args ipc.JoinMeshArgs, reply *string) error {
|
||||||
func (n *IpcHandler) JoinMesh(args *ipc.JoinMeshArgs, reply *string) error {
|
|
||||||
overrideConf := getOverrideConfiguration(&args.WgArgs)
|
overrideConf := getOverrideConfiguration(&args.WgArgs)
|
||||||
|
|
||||||
if n.Server.GetMeshManager().GetMesh(args.MeshId) != nil {
|
peerConnection, err := n.Server.GetConnectionManager().GetConnection(args.IpAdress)
|
||||||
return fmt.Errorf("user is already a part of the mesh")
|
|
||||||
}
|
|
||||||
|
|
||||||
peerConnection, err := n.Server.GetConnectionManager().GetConnection(args.IpAddress)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not join mesh %s", args.MeshId)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
client, err := peerConnection.GetClient()
|
client, err := peerConnection.GetClient()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not join mesh %s", args.MeshId)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
c := rpc.NewMeshCtrlServerClient(client)
|
c := rpc.NewMeshCtrlServerClient(client)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not join mesh %s", args.MeshId)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
configuration := n.Server.GetConfiguration()
|
configuration := n.Server.GetConfiguration()
|
||||||
@ -118,7 +112,7 @@ func (n *IpcHandler) JoinMesh(args *ipc.JoinMeshArgs, reply *string) error {
|
|||||||
meshReply, err := c.GetMesh(ctx, &rpc.GetMeshRequest{MeshId: args.MeshId})
|
meshReply, err := c.GetMesh(ctx, &rpc.GetMeshRequest{MeshId: args.MeshId})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not join mesh %s", args.MeshId)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = n.Server.GetMeshManager().AddMesh(&mesh.AddMeshParams{
|
err = n.Server.GetMeshManager().AddMesh(&mesh.AddMeshParams{
|
||||||
@ -129,7 +123,7 @@ func (n *IpcHandler) JoinMesh(args *ipc.JoinMeshArgs, reply *string) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not join mesh %s", args.MeshId)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = n.Server.GetMeshManager().AddSelf(&mesh.AddSelfParams{
|
err = n.Server.GetMeshManager().AddSelf(&mesh.AddSelfParams{
|
||||||
@ -139,24 +133,24 @@ func (n *IpcHandler) JoinMesh(args *ipc.JoinMeshArgs, reply *string) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not join mesh %s", args.MeshId)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*reply = fmt.Sprintf("Successfully Joined: %s", args.MeshId)
|
*reply = strconv.FormatBool(true)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LeaveMesh: leaves a mesh network
|
// LeaveMesh leaves a mesh network
|
||||||
func (n *IpcHandler) LeaveMesh(meshId string, reply *string) error {
|
func (n *IpcHandler) LeaveMesh(meshId string, reply *string) error {
|
||||||
err := n.Server.GetMeshManager().LeaveMesh(meshId)
|
err := n.Server.GetMeshManager().LeaveMesh(meshId)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
*reply = fmt.Sprintf("Left Mesh %s", meshId)
|
*reply = fmt.Sprintf("Left Mesh %s", meshId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMesh: get a mesh network at the given meshid
|
|
||||||
func (n *IpcHandler) GetMesh(meshId string, reply *ipc.GetMeshReply) error {
|
func (n *IpcHandler) GetMesh(meshId string, reply *ipc.GetMeshReply) error {
|
||||||
theMesh := n.Server.GetMeshManager().GetMesh(meshId)
|
theMesh := n.Server.GetMeshManager().GetMesh(meshId)
|
||||||
|
|
||||||
@ -188,7 +182,6 @@ func (n *IpcHandler) GetMesh(meshId string, reply *ipc.GetMeshReply) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query: perform a jmespath query
|
|
||||||
func (n *IpcHandler) Query(params ipc.QueryMesh, reply *string) error {
|
func (n *IpcHandler) Query(params ipc.QueryMesh, reply *string) error {
|
||||||
queryResponse, err := n.Server.GetQuerier().Query(params.MeshId, params.Query)
|
queryResponse, err := n.Server.GetQuerier().Query(params.MeshId, params.Query)
|
||||||
|
|
||||||
@ -200,59 +193,50 @@ func (n *IpcHandler) Query(params ipc.QueryMesh, reply *string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutDescription: change your description in the mesh
|
func (n *IpcHandler) PutDescription(description string, reply *string) error {
|
||||||
func (n *IpcHandler) PutDescription(args ipc.PutDescriptionArgs, reply *string) error {
|
err := n.Server.GetMeshManager().SetDescription(description)
|
||||||
err := n.Server.GetMeshManager().SetDescription(args.MeshId, args.Description)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*reply = fmt.Sprintf("set description to %s for %s", args.Description, args.MeshId)
|
*reply = fmt.Sprintf("Set description to %s", description)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutAlias: put your aliasin the mesh
|
func (n *IpcHandler) PutAlias(alias string, reply *string) error {
|
||||||
func (n *IpcHandler) PutAlias(args ipc.PutAliasArgs, reply *string) error {
|
err := n.Server.GetMeshManager().SetAlias(alias)
|
||||||
if args.Alias == "" {
|
|
||||||
return fmt.Errorf("alias not provided")
|
|
||||||
}
|
|
||||||
|
|
||||||
err := n.Server.GetMeshManager().SetAlias(args.MeshId, args.Alias)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("could not set alias: %s", args.Alias)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*reply = fmt.Sprintf("Set alias to %s", args.Alias)
|
*reply = fmt.Sprintf("Set alias to %s", alias)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutService: place a service in the mesh
|
|
||||||
func (n *IpcHandler) PutService(service ipc.PutServiceArgs, reply *string) error {
|
func (n *IpcHandler) PutService(service ipc.PutServiceArgs, reply *string) error {
|
||||||
err := n.Server.GetMeshManager().SetService(service.MeshId, service.Service, service.Value)
|
err := n.Server.GetMeshManager().SetService(service.Service, service.Value)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*reply = fmt.Sprintf("Set service %s in %s to %s", service.Service, service.MeshId, service.Value)
|
*reply = "success"
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteService: withtract a service in the mesh
|
func (n *IpcHandler) DeleteService(service string, reply *string) error {
|
||||||
func (n *IpcHandler) DeleteService(service ipc.DeleteServiceArgs, reply *string) error {
|
err := n.Server.GetMeshManager().RemoveService(service)
|
||||||
err := n.Server.GetMeshManager().RemoveService(service.MeshId, service.Service)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
*reply = fmt.Sprintf("Removed service %s from %s", service.Service, service.MeshId)
|
*reply = "success"
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RobinIpcParams: parameters required to construct a new mesh network
|
|
||||||
type RobinIpcParams struct {
|
type RobinIpcParams struct {
|
||||||
CtrlServer ctrlserver.CtrlServer
|
CtrlServer ctrlserver.CtrlServer
|
||||||
}
|
}
|
@ -3,10 +3,10 @@ package robin
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ipc"
|
"github.com/tim-beatham/wgmesh/pkg/ipc"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getRequester() *IpcHandler {
|
func getRequester() *IpcHandler {
|
@ -4,17 +4,15 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/ctrlserver"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/rpc"
|
"github.com/tim-beatham/wgmesh/pkg/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WgRpc: represents a WireGuard rpc call
|
|
||||||
type WgRpc struct {
|
type WgRpc struct {
|
||||||
rpc.UnimplementedMeshCtrlServerServer
|
rpc.UnimplementedMeshCtrlServerServer
|
||||||
Server *ctrlserver.MeshCtrlServer
|
Server *ctrlserver.MeshCtrlServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMesh: serialise the mesh network into bytes
|
|
||||||
func (m *WgRpc) GetMesh(ctx context.Context, request *rpc.GetMeshRequest) (*rpc.GetMeshReply, error) {
|
func (m *WgRpc) GetMesh(ctx context.Context, request *rpc.GetMeshRequest) (*rpc.GetMeshReply, error) {
|
||||||
mesh := m.Server.MeshManager.GetMesh(request.MeshId)
|
mesh := m.Server.MeshManager.GetMesh(request.MeshId)
|
||||||
|
|
1
pkg/robin/responder_test.go
Normal file
1
pkg/robin/responder_test.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package robin
|
@ -1,11 +1,10 @@
|
|||||||
package route
|
package route
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RouteInstaller: install the routes to the given interface
|
|
||||||
type RouteInstaller interface {
|
type RouteInstaller interface {
|
||||||
InstallRoutes(devName string, routes ...lib.Route) error
|
InstallRoutes(devName string, routes ...lib.Route) error
|
||||||
}
|
}
|
||||||
@ -20,8 +19,6 @@ func (r *RouteInstallerImpl) InstallRoutes(devName string, routes ...lib.Route)
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer rtnl.Close()
|
|
||||||
|
|
||||||
err = rtnl.DeleteRoutes(devName, unix.AF_INET6, routes...)
|
err = rtnl.DeleteRoutes(devName, unix.AF_INET6, routes...)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
235
pkg/rpc/authentication.pb.go
Normal file
235
pkg/rpc/authentication.pb.go
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.28.1
|
||||||
|
// protoc v3.21.12
|
||||||
|
// source: pkg/grpc/ctrlserver/authentication.proto
|
||||||
|
|
||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type JoinAuthMeshRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
MeshId string `protobuf:"bytes,1,opt,name=meshId,proto3" json:"meshId,omitempty"`
|
||||||
|
Alias string `protobuf:"bytes,2,opt,name=alias,proto3" json:"alias,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshRequest) Reset() {
|
||||||
|
*x = JoinAuthMeshRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_pkg_grpc_ctrlserver_authentication_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*JoinAuthMeshRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_pkg_grpc_ctrlserver_authentication_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use JoinAuthMeshRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*JoinAuthMeshRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_pkg_grpc_ctrlserver_authentication_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshRequest) GetMeshId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.MeshId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshRequest) GetAlias() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Alias
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type JoinAuthMeshReply struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Success bool `protobuf:"varint,1,opt,name=success,proto3" json:"success,omitempty"`
|
||||||
|
Token *string `protobuf:"bytes,2,opt,name=token,proto3,oneof" json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshReply) Reset() {
|
||||||
|
*x = JoinAuthMeshReply{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_pkg_grpc_ctrlserver_authentication_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshReply) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*JoinAuthMeshReply) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshReply) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_pkg_grpc_ctrlserver_authentication_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use JoinAuthMeshReply.ProtoReflect.Descriptor instead.
|
||||||
|
func (*JoinAuthMeshReply) Descriptor() ([]byte, []int) {
|
||||||
|
return file_pkg_grpc_ctrlserver_authentication_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshReply) GetSuccess() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.Success
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *JoinAuthMeshReply) GetToken() string {
|
||||||
|
if x != nil && x.Token != nil {
|
||||||
|
return *x.Token
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_pkg_grpc_ctrlserver_authentication_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_pkg_grpc_ctrlserver_authentication_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x28, 0x70, 0x6b, 0x67, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x74, 0x72, 0x6c, 0x73,
|
||||||
|
0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61,
|
||||||
|
0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x72, 0x70, 0x63, 0x74,
|
||||||
|
0x79, 0x70, 0x65, 0x73, 0x22, 0x43, 0x0a, 0x13, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x75, 0x74, 0x68,
|
||||||
|
0x4d, 0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d,
|
||||||
|
0x65, 0x73, 0x68, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x73,
|
||||||
|
0x68, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x18, 0x02, 0x20, 0x01,
|
||||||
|
0x28, 0x09, 0x52, 0x05, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x22, 0x52, 0x0a, 0x11, 0x4a, 0x6f, 0x69,
|
||||||
|
0x6e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65, 0x73, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18,
|
||||||
|
0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
|
0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x19, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65,
|
||||||
|
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
||||||
|
0x88, 0x01, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0x5a, 0x0a,
|
||||||
|
0x0e, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
|
||||||
|
0x48, 0x0a, 0x08, 0x4a, 0x6f, 0x69, 0x6e, 0x4d, 0x65, 0x73, 0x68, 0x12, 0x1d, 0x2e, 0x72, 0x70,
|
||||||
|
0x63, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x4d,
|
||||||
|
0x65, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x72, 0x70, 0x63,
|
||||||
|
0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x4a, 0x6f, 0x69, 0x6e, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x65,
|
||||||
|
0x73, 0x68, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x09, 0x5a, 0x07, 0x70, 0x6b, 0x67,
|
||||||
|
0x2f, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_rawDescOnce sync.Once
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_rawDescData = file_pkg_grpc_ctrlserver_authentication_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_pkg_grpc_ctrlserver_authentication_proto_rawDescGZIP() []byte {
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_rawDescOnce.Do(func() {
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_grpc_ctrlserver_authentication_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_pkg_grpc_ctrlserver_authentication_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_pkg_grpc_ctrlserver_authentication_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
|
var file_pkg_grpc_ctrlserver_authentication_proto_goTypes = []interface{}{
|
||||||
|
(*JoinAuthMeshRequest)(nil), // 0: rpctypes.JoinAuthMeshRequest
|
||||||
|
(*JoinAuthMeshReply)(nil), // 1: rpctypes.JoinAuthMeshReply
|
||||||
|
}
|
||||||
|
var file_pkg_grpc_ctrlserver_authentication_proto_depIdxs = []int32{
|
||||||
|
0, // 0: rpctypes.Authentication.JoinMesh:input_type -> rpctypes.JoinAuthMeshRequest
|
||||||
|
1, // 1: rpctypes.Authentication.JoinMesh:output_type -> rpctypes.JoinAuthMeshReply
|
||||||
|
1, // [1:2] is the sub-list for method output_type
|
||||||
|
0, // [0:1] is the sub-list for method input_type
|
||||||
|
0, // [0:0] is the sub-list for extension type_name
|
||||||
|
0, // [0:0] is the sub-list for extension extendee
|
||||||
|
0, // [0:0] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_pkg_grpc_ctrlserver_authentication_proto_init() }
|
||||||
|
func file_pkg_grpc_ctrlserver_authentication_proto_init() {
|
||||||
|
if File_pkg_grpc_ctrlserver_authentication_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*JoinAuthMeshRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*JoinAuthMeshReply); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_msgTypes[1].OneofWrappers = []interface{}{}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_pkg_grpc_ctrlserver_authentication_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 2,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_pkg_grpc_ctrlserver_authentication_proto_goTypes,
|
||||||
|
DependencyIndexes: file_pkg_grpc_ctrlserver_authentication_proto_depIdxs,
|
||||||
|
MessageInfos: file_pkg_grpc_ctrlserver_authentication_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_pkg_grpc_ctrlserver_authentication_proto = out.File
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_rawDesc = nil
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_goTypes = nil
|
||||||
|
file_pkg_grpc_ctrlserver_authentication_proto_depIdxs = nil
|
||||||
|
}
|
105
pkg/rpc/authentication_grpc.pb.go
Normal file
105
pkg/rpc/authentication_grpc.pb.go
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
|
// - protoc v3.21.12
|
||||||
|
// source: pkg/grpc/ctrlserver/authentication.proto
|
||||||
|
|
||||||
|
package rpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.32.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion7
|
||||||
|
|
||||||
|
// AuthenticationClient is the client API for Authentication service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type AuthenticationClient interface {
|
||||||
|
JoinMesh(ctx context.Context, in *JoinAuthMeshRequest, opts ...grpc.CallOption) (*JoinAuthMeshReply, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type authenticationClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuthenticationClient(cc grpc.ClientConnInterface) AuthenticationClient {
|
||||||
|
return &authenticationClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *authenticationClient) JoinMesh(ctx context.Context, in *JoinAuthMeshRequest, opts ...grpc.CallOption) (*JoinAuthMeshReply, error) {
|
||||||
|
out := new(JoinAuthMeshReply)
|
||||||
|
err := c.cc.Invoke(ctx, "/rpctypes.Authentication/JoinMesh", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AuthenticationServer is the server API for Authentication service.
|
||||||
|
// All implementations must embed UnimplementedAuthenticationServer
|
||||||
|
// for forward compatibility
|
||||||
|
type AuthenticationServer interface {
|
||||||
|
JoinMesh(context.Context, *JoinAuthMeshRequest) (*JoinAuthMeshReply, error)
|
||||||
|
mustEmbedUnimplementedAuthenticationServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedAuthenticationServer must be embedded to have forward compatible implementations.
|
||||||
|
type UnimplementedAuthenticationServer struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UnimplementedAuthenticationServer) JoinMesh(context.Context, *JoinAuthMeshRequest) (*JoinAuthMeshReply, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method JoinMesh not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedAuthenticationServer) mustEmbedUnimplementedAuthenticationServer() {}
|
||||||
|
|
||||||
|
// UnsafeAuthenticationServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to AuthenticationServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeAuthenticationServer interface {
|
||||||
|
mustEmbedUnimplementedAuthenticationServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterAuthenticationServer(s grpc.ServiceRegistrar, srv AuthenticationServer) {
|
||||||
|
s.RegisterService(&Authentication_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Authentication_JoinMesh_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(JoinAuthMeshRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(AuthenticationServer).JoinMesh(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/rpctypes.Authentication/JoinMesh",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(AuthenticationServer).JoinMesh(ctx, req.(*JoinAuthMeshRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentication_ServiceDesc is the grpc.ServiceDesc for Authentication service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var Authentication_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "rpctypes.Authentication",
|
||||||
|
HandlerType: (*AuthenticationServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "JoinMesh",
|
||||||
|
Handler: _Authentication_JoinMesh_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "pkg/grpc/ctrlserver/authentication.proto",
|
||||||
|
}
|
@ -1,76 +1,66 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/conf"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conn"
|
"github.com/tim-beatham/wgmesh/pkg/conn"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Syncer: picks random nodes from the meshs
|
// Syncer: picks random nodes from the meshs
|
||||||
type Syncer interface {
|
type Syncer interface {
|
||||||
Sync(theMesh mesh.MeshProvider) (bool, error)
|
Sync(meshId string) error
|
||||||
SyncMeshes() error
|
SyncMeshes() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncerImpl: implementation of a syncer to sync meshes
|
|
||||||
type SyncerImpl struct {
|
type SyncerImpl struct {
|
||||||
meshManager mesh.MeshManager
|
manager mesh.MeshManager
|
||||||
requester SyncRequester
|
requester SyncRequester
|
||||||
infectionCount int
|
infectionCount int
|
||||||
syncCount int
|
syncCount int
|
||||||
cluster conn.ConnCluster
|
cluster conn.ConnCluster
|
||||||
configuration *conf.DaemonConfiguration
|
conf *conf.DaemonConfiguration
|
||||||
lastSync map[string]int64
|
lastSync map[string]uint64
|
||||||
lastPoll map[string]int64
|
|
||||||
lastSyncLock sync.RWMutex
|
|
||||||
lastPollLock sync.RWMutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync: Sync with random nodes. Returns true if there was changes false otherwise
|
// Sync: Sync random nodes
|
||||||
func (s *SyncerImpl) Sync(correspondingMesh mesh.MeshProvider) (bool, error) {
|
func (s *SyncerImpl) Sync(meshId string) error {
|
||||||
if correspondingMesh == nil {
|
|
||||||
return false, fmt.Errorf("mesh provided was nil cannot sync nil mesh")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Self can be nil if the node is removed
|
// Self can be nil if the node is removed
|
||||||
selfID := s.meshManager.GetPublicKey()
|
self, _ := s.manager.GetSelf(meshId)
|
||||||
self, _ := correspondingMesh.GetNode(selfID.String())
|
|
||||||
|
correspondingMesh := s.manager.GetMesh(meshId)
|
||||||
|
|
||||||
correspondingMesh.Prune()
|
correspondingMesh.Prune()
|
||||||
|
|
||||||
if correspondingMesh.HasChanges() {
|
if self != nil && self.GetType() == conf.PEER_ROLE && !s.manager.HasChanges(meshId) && s.infectionCount == 0 {
|
||||||
logging.Log.WriteInfof("meshes %s has changes", correspondingMesh.GetMeshId())
|
logging.Log.WriteInfof("No changes for %s", meshId)
|
||||||
}
|
|
||||||
|
|
||||||
// If removed sync with other nodes to gossip the node is removed
|
// If not synchronised in certain pull from random neighbour
|
||||||
if self != nil && self.GetType() == conf.PEER_ROLE && !correspondingMesh.HasChanges() && s.infectionCount == 0 {
|
if uint64(time.Now().Unix())-s.lastSync[meshId] > 20 {
|
||||||
logging.Log.WriteInfof("no changes for %s", correspondingMesh.GetMeshId())
|
return s.Pull(meshId)
|
||||||
|
|
||||||
// If not synchronised in certain time pull from random neighbour
|
|
||||||
if s.configuration.PullInterval != 0 && time.Now().Unix()-s.lastSync[correspondingMesh.GetMeshId()] > int64(s.configuration.PullInterval) {
|
|
||||||
return s.Pull(self, correspondingMesh)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
before := time.Now()
|
before := time.Now()
|
||||||
|
s.manager.GetRouteManager().UpdateRoutes()
|
||||||
|
|
||||||
publicKey := s.meshManager.GetPublicKey()
|
publicKey := s.manager.GetPublicKey()
|
||||||
nodeNames := correspondingMesh.GetPeers()
|
nodeNames := correspondingMesh.GetPeers()
|
||||||
|
|
||||||
nodeNames = lib.Filter(nodeNames, func(s string) bool {
|
if self != nil {
|
||||||
// Filter our only public key out so we dont sync with ourself
|
nodeNames = lib.Filter(nodeNames, func(s string) bool {
|
||||||
return s != publicKey.String()
|
return s != mesh.NodeID(self)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var gossipNodes []string
|
var gossipNodes []string
|
||||||
|
|
||||||
@ -79,187 +69,132 @@ func (s *SyncerImpl) Sync(correspondingMesh mesh.MeshProvider) (bool, error) {
|
|||||||
neighbours := s.cluster.GetNeighbours(nodeNames, publicKey.String())
|
neighbours := s.cluster.GetNeighbours(nodeNames, publicKey.String())
|
||||||
|
|
||||||
if len(neighbours) == 0 {
|
if len(neighbours) == 0 {
|
||||||
return false, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peer with 2 nodes so that there is redundancy in
|
redundancyLength := min(len(neighbours), 3)
|
||||||
// the situation the node leaves pre-emptively
|
|
||||||
redundancyLength := min(len(neighbours), 2)
|
|
||||||
gossipNodes = neighbours[:redundancyLength]
|
gossipNodes = neighbours[:redundancyLength]
|
||||||
} else {
|
} else {
|
||||||
neighbours := s.cluster.GetNeighbours(nodeNames, publicKey.String())
|
neighbours := s.cluster.GetNeighbours(nodeNames, publicKey.String())
|
||||||
gossipNodes = lib.RandomSubsetOfLength(neighbours, s.configuration.Branch)
|
gossipNodes = lib.RandomSubsetOfLength(neighbours, s.conf.BranchRate)
|
||||||
|
|
||||||
if len(nodeNames) > s.configuration.ClusterSize && rand.Float64() < s.configuration.InterClusterChance {
|
if len(nodeNames) > s.conf.ClusterSize && rand.Float64() < s.conf.InterClusterChance {
|
||||||
gossipNodes[len(gossipNodes)-1] = s.cluster.GetInterCluster(nodeNames, publicKey.String())
|
gossipNodes[len(gossipNodes)-1] = s.cluster.GetInterCluster(nodeNames, publicKey.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var succeeded bool = false
|
var succeeded bool = false
|
||||||
|
|
||||||
|
// Do this synchronously to conserve bandwidth
|
||||||
for _, node := range gossipNodes {
|
for _, node := range gossipNodes {
|
||||||
correspondingPeer, err := correspondingMesh.GetNode(node)
|
correspondingPeer := s.manager.GetNode(meshId, node)
|
||||||
|
|
||||||
if correspondingPeer == nil || err != nil {
|
if correspondingPeer == nil {
|
||||||
logging.Log.WriteErrorf("node %s does not exist", node)
|
logging.Log.WriteErrorf("node %s does not exist", node)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.requester.SyncMesh(correspondingMesh, correspondingPeer)
|
err := s.requester.SyncMesh(meshId, correspondingPeer)
|
||||||
|
|
||||||
if err == nil || err == io.EOF {
|
if err == nil || err == io.EOF {
|
||||||
succeeded = true
|
succeeded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log.WriteErrorf(err.Error())
|
logging.Log.WriteInfof(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.syncCount++
|
s.syncCount++
|
||||||
logging.Log.WriteInfof("sync time: %v", time.Since(before))
|
logging.Log.WriteInfof("SYNC TIME: %v", time.Since(before))
|
||||||
logging.Log.WriteInfof("number of syncs: %d", s.syncCount)
|
logging.Log.WriteInfof("SYNC COUNT: %d", s.syncCount)
|
||||||
|
|
||||||
s.infectionCount = ((s.configuration.InfectionCount + s.infectionCount - 1) % s.configuration.InfectionCount)
|
s.infectionCount = ((s.conf.InfectionCount + s.infectionCount - 1) % s.conf.InfectionCount)
|
||||||
|
|
||||||
if !succeeded {
|
if !succeeded {
|
||||||
|
// If could not gossip with anyone then repeat.
|
||||||
s.infectionCount++
|
s.infectionCount++
|
||||||
}
|
}
|
||||||
|
|
||||||
correspondingMesh.SaveChanges()
|
s.manager.GetMesh(meshId).SaveChanges()
|
||||||
|
s.lastSync[meshId] = uint64(time.Now().Unix())
|
||||||
|
|
||||||
s.lastSyncLock.Lock()
|
logging.Log.WriteInfof("UPDATING WG CONF")
|
||||||
s.lastSync[correspondingMesh.GetMeshId()] = time.Now().Unix()
|
err := s.manager.ApplyConfig()
|
||||||
s.lastSyncLock.Unlock()
|
|
||||||
return true, nil
|
if err != nil {
|
||||||
|
logging.Log.WriteInfof("Failed to update config %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pull one node in the cluster, if there has not been message dissemination
|
// Pull one node in the cluster, if there has not been message dissemination
|
||||||
// in a certain period of time pull a random node within the cluster
|
// in a certain period of time pull a random node within the cluster
|
||||||
func (s *SyncerImpl) Pull(self mesh.MeshNode, mesh mesh.MeshProvider) (bool, error) {
|
func (s *SyncerImpl) Pull(meshId string) error {
|
||||||
peers := mesh.GetPeers()
|
mesh := s.manager.GetMesh(meshId)
|
||||||
|
self, err := s.manager.GetSelf(meshId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
pubKey, _ := self.GetPublicKey()
|
pubKey, _ := self.GetPublicKey()
|
||||||
|
|
||||||
|
if mesh == nil {
|
||||||
|
return errors.New("mesh is nil, invalid operation")
|
||||||
|
}
|
||||||
|
|
||||||
|
peers := mesh.GetPeers()
|
||||||
neighbours := s.cluster.GetNeighbours(peers, pubKey.String())
|
neighbours := s.cluster.GetNeighbours(peers, pubKey.String())
|
||||||
neighbour := lib.RandomSubsetOfLength(neighbours, 1)
|
neighbour := lib.RandomSubsetOfLength(neighbours, 1)
|
||||||
|
|
||||||
if len(neighbour) == 0 {
|
if len(neighbour) == 0 {
|
||||||
logging.Log.WriteInfof("no neighbours")
|
logging.Log.WriteInfof("no neighbours")
|
||||||
return false, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.Log.WriteInfof("pulling from node %s", neighbour[0])
|
logging.Log.WriteInfof("PULLING from node %s", neighbour[0])
|
||||||
|
|
||||||
pullNode, err := mesh.GetNode(neighbour[0])
|
pullNode, err := mesh.GetNode(neighbour[0])
|
||||||
|
|
||||||
if err != nil || pullNode == nil {
|
if err != nil || pullNode == nil {
|
||||||
return false, fmt.Errorf("node %s does not exist in the mesh", neighbour[0])
|
return fmt.Errorf("node %s does not exist in the mesh", neighbour[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.requester.SyncMesh(mesh, pullNode)
|
err = s.requester.SyncMesh(meshId, pullNode)
|
||||||
|
|
||||||
if err == nil || err == io.EOF {
|
if err == nil || err == io.EOF {
|
||||||
s.lastSync[mesh.GetMeshId()] = time.Now().Unix()
|
s.lastSync[meshId] = uint64(time.Now().Unix())
|
||||||
} else {
|
} else {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.syncCount++
|
s.syncCount++
|
||||||
|
return nil
|
||||||
changes := mesh.HasChanges()
|
|
||||||
return changes, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncMeshes: Sync all meshes
|
// SyncMeshes: Sync all meshes
|
||||||
func (s *SyncerImpl) SyncMeshes() error {
|
func (s *SyncerImpl) SyncMeshes() error {
|
||||||
var wg sync.WaitGroup
|
for meshId := range s.manager.GetMeshes() {
|
||||||
|
err := s.Sync(meshId)
|
||||||
meshes := s.meshManager.GetMeshes()
|
|
||||||
|
|
||||||
s.lastPollLock.Lock()
|
|
||||||
meshesToSync := lib.Filter(lib.MapValues(meshes), func(mesh mesh.MeshProvider) bool {
|
|
||||||
return time.Now().Unix()-s.lastPoll[mesh.GetMeshId()] >= int64(s.configuration.SyncInterval)
|
|
||||||
})
|
|
||||||
s.lastPollLock.Unlock()
|
|
||||||
|
|
||||||
changes := make(chan bool, len(meshesToSync))
|
|
||||||
|
|
||||||
for i := 0; i < len(meshesToSync); {
|
|
||||||
wg.Add(1)
|
|
||||||
|
|
||||||
sync := func(index int) {
|
|
||||||
defer wg.Done()
|
|
||||||
|
|
||||||
var hasChanges bool = false
|
|
||||||
|
|
||||||
mesh := meshesToSync[index]
|
|
||||||
|
|
||||||
hasChanges, err := s.Sync(mesh)
|
|
||||||
changes <- hasChanges
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logging.Log.WriteErrorf(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
s.lastPollLock.Lock()
|
|
||||||
s.lastPoll[mesh.GetMeshId()] = time.Now().Unix()
|
|
||||||
s.lastPollLock.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
go sync(i)
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
hasChanges := false
|
|
||||||
|
|
||||||
for i := 0; i < len(changes); i++ {
|
|
||||||
if <-changes {
|
|
||||||
hasChanges = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
|
|
||||||
err = s.meshManager.GetRouteManager().UpdateRoutes()
|
|
||||||
if err != nil {
|
|
||||||
logging.Log.WriteErrorf("update routes failed %s", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasChanges {
|
|
||||||
logging.Log.WriteInfof("updating the WireGuard configuration")
|
|
||||||
err = s.meshManager.ApplyConfig()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log.WriteErrorf("failed to update config %s", err.Error())
|
logging.Log.WriteErrorf(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewSyncerParams struct {
|
func NewSyncer(m mesh.MeshManager, conf *conf.DaemonConfiguration, r SyncRequester) Syncer {
|
||||||
MeshManager mesh.MeshManager
|
cluster, _ := conn.NewConnCluster(conf.ClusterSize)
|
||||||
ConnectionManager conn.ConnectionManager
|
|
||||||
Configuration *conf.DaemonConfiguration
|
|
||||||
Requester SyncRequester
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSyncer(params *NewSyncerParams) Syncer {
|
|
||||||
cluster, _ := conn.NewConnCluster(params.Configuration.ClusterSize)
|
|
||||||
syncRequester := NewSyncRequester(NewSyncRequesterParams{
|
|
||||||
MeshManager: params.MeshManager,
|
|
||||||
ConnectionManager: params.ConnectionManager,
|
|
||||||
Configuration: params.Configuration,
|
|
||||||
})
|
|
||||||
|
|
||||||
return &SyncerImpl{
|
return &SyncerImpl{
|
||||||
meshManager: params.MeshManager,
|
manager: m,
|
||||||
configuration: params.Configuration,
|
conf: conf,
|
||||||
requester: syncRequester,
|
requester: r,
|
||||||
infectionCount: 0,
|
infectionCount: 0,
|
||||||
syncCount: 0,
|
syncCount: 0,
|
||||||
cluster: cluster,
|
cluster: cluster,
|
||||||
lastSync: make(map[string]int64),
|
lastSync: make(map[string]uint64)}
|
||||||
lastPoll: make(map[string]int64)}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conn"
|
"github.com/tim-beatham/wgmesh/pkg/conn"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SyncErrorHandler: Handles errors when attempting to sync
|
// SyncErrorHandler: Handles errors when attempting to sync
|
||||||
type SyncErrorHandler interface {
|
type SyncErrorHandler interface {
|
||||||
Handle(mesh mesh.MeshProvider, endpoint string, err error) bool
|
Handle(meshId string, endpoint string, err error) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyncErrorHandlerImpl Is an implementation of the SyncErrorHandler
|
// SyncErrorHandlerImpl Is an implementation of the SyncErrorHandler
|
||||||
@ -19,7 +19,8 @@ type SyncErrorHandlerImpl struct {
|
|||||||
connManager conn.ConnectionManager
|
connManager conn.ConnectionManager
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SyncErrorHandlerImpl) handleFailed(mesh mesh.MeshProvider, nodeId string) bool {
|
func (s *SyncErrorHandlerImpl) handleFailed(meshId string, nodeId string) bool {
|
||||||
|
mesh := s.meshManager.GetMesh(meshId)
|
||||||
mesh.Mark(nodeId)
|
mesh.Mark(nodeId)
|
||||||
node, err := mesh.GetNode(nodeId)
|
node, err := mesh.GetNode(nodeId)
|
||||||
|
|
||||||
@ -29,7 +30,13 @@ func (s *SyncErrorHandlerImpl) handleFailed(mesh mesh.MeshProvider, nodeId strin
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SyncErrorHandlerImpl) handleDeadlineExceeded(mesh mesh.MeshProvider, nodeId string) bool {
|
func (s *SyncErrorHandlerImpl) handleDeadlineExceeded(meshId string, nodeId string) bool {
|
||||||
|
mesh := s.meshManager.GetMesh(meshId)
|
||||||
|
|
||||||
|
if mesh == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
node, err := mesh.GetNode(nodeId)
|
node, err := mesh.GetNode(nodeId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -40,16 +47,16 @@ func (s *SyncErrorHandlerImpl) handleDeadlineExceeded(mesh mesh.MeshProvider, no
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SyncErrorHandlerImpl) Handle(mesh mesh.MeshProvider, nodeId string, err error) bool {
|
func (s *SyncErrorHandlerImpl) Handle(meshId string, nodeId string, err error) bool {
|
||||||
errStatus, _ := status.FromError(err)
|
errStatus, _ := status.FromError(err)
|
||||||
|
|
||||||
logging.Log.WriteInfof("Handled gRPC error: %s", errStatus.Message())
|
logging.Log.WriteInfof("Handled gRPC error: %s", errStatus.Message())
|
||||||
|
|
||||||
switch errStatus.Code() {
|
switch errStatus.Code() {
|
||||||
case codes.Unavailable, codes.Unknown, codes.Internal, codes.NotFound:
|
case codes.Unavailable, codes.Unknown, codes.Internal, codes.NotFound:
|
||||||
return s.handleFailed(mesh, nodeId)
|
return s.handleFailed(meshId, nodeId)
|
||||||
case codes.DeadlineExceeded:
|
case codes.DeadlineExceeded:
|
||||||
return s.handleDeadlineExceeded(mesh, nodeId)
|
return s.handleDeadlineExceeded(meshId, nodeId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -2,44 +2,30 @@ package sync
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conf"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/conn"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/rpc"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/rpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// SyncRequester: coordinates the syncing of meshes
|
// SyncRequester: coordinates the syncing of meshes
|
||||||
type SyncRequester interface {
|
type SyncRequester interface {
|
||||||
SyncMesh(mesh mesh.MeshProvider, meshNode mesh.MeshNode) error
|
GetMesh(meshId string, ifName string, port int, endPoint string) error
|
||||||
|
SyncMesh(meshid string, meshNode mesh.MeshNode) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type SyncRequesterImpl struct {
|
type SyncRequesterImpl struct {
|
||||||
manager mesh.MeshManager
|
server *ctrlserver.MeshCtrlServer
|
||||||
connectionManager conn.ConnectionManager
|
errorHdlr SyncErrorHandler
|
||||||
configuration *conf.DaemonConfiguration
|
|
||||||
errorHdlr SyncErrorHandler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleErr: handleGrpc errors
|
// GetMesh: Retrieves the local state of the mesh at the endpoint
|
||||||
func (s *SyncRequesterImpl) handleErr(mesh mesh.MeshProvider, pubKey string, err error) error {
|
func (s *SyncRequesterImpl) GetMesh(meshId string, ifName string, port int, endPoint string) error {
|
||||||
ok := s.errorHdlr.Handle(mesh, pubKey, err)
|
peerConnection, err := s.server.ConnectionManager.GetConnection(endPoint)
|
||||||
|
|
||||||
if ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SyncMesh: Proactively send a sync request to the other mesh
|
|
||||||
func (s *SyncRequesterImpl) SyncMesh(mesh mesh.MeshProvider, meshNode mesh.MeshNode) error {
|
|
||||||
endpoint := meshNode.GetHostEndpoint()
|
|
||||||
pubKey, _ := meshNode.GetPublicKey()
|
|
||||||
|
|
||||||
peerConnection, err := s.connectionManager.GetConnection(endpoint)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -53,7 +39,59 @@ func (s *SyncRequesterImpl) SyncMesh(mesh mesh.MeshProvider, meshNode mesh.MeshN
|
|||||||
|
|
||||||
c := rpc.NewSyncServiceClient(client)
|
c := rpc.NewSyncServiceClient(client)
|
||||||
|
|
||||||
syncTimeOut := float64(s.configuration.SyncInterval) * float64(time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
reply, err := c.GetConf(ctx, &rpc.GetConfRequest{MeshId: meshId})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.server.MeshManager.AddMesh(&mesh.AddMeshParams{
|
||||||
|
MeshId: meshId,
|
||||||
|
WgPort: port,
|
||||||
|
MeshBytes: reply.Mesh,
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SyncRequesterImpl) handleErr(meshId, pubKey string, err error) error {
|
||||||
|
ok := s.errorHdlr.Handle(meshId, pubKey, err)
|
||||||
|
|
||||||
|
if ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyncMesh: Proactively send a sync request to the other mesh
|
||||||
|
func (s *SyncRequesterImpl) SyncMesh(meshId string, meshNode mesh.MeshNode) error {
|
||||||
|
endpoint := meshNode.GetHostEndpoint()
|
||||||
|
pubKey, _ := meshNode.GetPublicKey()
|
||||||
|
|
||||||
|
peerConnection, err := s.server.ConnectionManager.GetConnection(endpoint)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := peerConnection.GetClient()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh := s.server.MeshManager.GetMesh(meshId)
|
||||||
|
|
||||||
|
if mesh == nil {
|
||||||
|
return errors.New("mesh does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
c := rpc.NewSyncServiceClient(client)
|
||||||
|
|
||||||
|
syncTimeOut := float64(s.server.Conf.SyncRate) * float64(time.Second)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(syncTimeOut))
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(syncTimeOut))
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@ -61,11 +99,11 @@ func (s *SyncRequesterImpl) SyncMesh(mesh mesh.MeshProvider, meshNode mesh.MeshN
|
|||||||
err = s.syncMesh(mesh, ctx, c)
|
err = s.syncMesh(mesh, ctx, c)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.handleErr(mesh, pubKey.String(), err)
|
return s.handleErr(meshId, pubKey.String(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
logging.Log.WriteInfof("synced with node: %s meshId: %s\n", endpoint, mesh.GetMeshId())
|
logging.Log.WriteInfof("Synced with node: %s meshId: %s\n", endpoint, meshId)
|
||||||
return err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SyncRequesterImpl) syncMesh(mesh mesh.MeshProvider, ctx context.Context, client rpc.SyncServiceClient) error {
|
func (s *SyncRequesterImpl) syncMesh(mesh mesh.MeshProvider, ctx context.Context, client rpc.SyncServiceClient) error {
|
||||||
@ -89,7 +127,7 @@ func (s *SyncRequesterImpl) syncMesh(mesh mesh.MeshProvider, ctx context.Context
|
|||||||
in, err := stream.Recv()
|
in, err := stream.Recv()
|
||||||
|
|
||||||
if err != nil && err != io.EOF {
|
if err != nil && err != io.EOF {
|
||||||
logging.Log.WriteInfof("stream recv error: %s\n", err.Error())
|
logging.Log.WriteInfof("Stream recv error: %s\n", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,7 +136,7 @@ func (s *SyncRequesterImpl) syncMesh(mesh mesh.MeshProvider, ctx context.Context
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logging.Log.WriteInfof("syncer recv error: %s\n", err.Error())
|
logging.Log.WriteInfof("Syncer recv error: %s\n", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,17 +150,7 @@ func (s *SyncRequesterImpl) syncMesh(mesh mesh.MeshProvider, ctx context.Context
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewSyncRequesterParams struct {
|
func NewSyncRequester(s *ctrlserver.MeshCtrlServer) SyncRequester {
|
||||||
MeshManager mesh.MeshManager
|
errorHdlr := NewSyncErrorHandler(s.MeshManager, s.ConnectionManager)
|
||||||
ConnectionManager conn.ConnectionManager
|
return &SyncRequesterImpl{server: s, errorHdlr: errorHdlr}
|
||||||
Configuration *conf.DaemonConfiguration
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewSyncRequester(params NewSyncRequesterParams) SyncRequester {
|
|
||||||
errorHdlr := NewSyncErrorHandler(params.MeshManager, params.ConnectionManager)
|
|
||||||
return &SyncRequesterImpl{manager: params.MeshManager,
|
|
||||||
connectionManager: params.ConnectionManager,
|
|
||||||
configuration: params.Configuration,
|
|
||||||
errorHdlr: errorHdlr,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
18
pkg/sync/syncscheduler.go
Normal file
18
pkg/sync/syncscheduler.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package sync
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Run implements SyncScheduler.
|
||||||
|
func syncFunction(syncer Syncer) lib.TimerFunc {
|
||||||
|
return func() error {
|
||||||
|
syncer.SyncMeshes()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSyncScheduler(s *ctrlserver.MeshCtrlServer, syncRequester SyncRequester, syncer Syncer) *lib.Timer {
|
||||||
|
return lib.NewTimer(syncFunction(syncer), s.Conf.SyncRate)
|
||||||
|
}
|
@ -6,18 +6,19 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/mesh"
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
"github.com/tim-beatham/smegmesh/pkg/rpc"
|
"github.com/tim-beatham/wgmesh/pkg/mesh"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SyncServiceImpl struct {
|
type SyncServiceImpl struct {
|
||||||
rpc.UnimplementedSyncServiceServer
|
rpc.UnimplementedSyncServiceServer
|
||||||
MeshManager mesh.MeshManager
|
Server *ctrlserver.MeshCtrlServer
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMesh: Gets a nodes local mesh configuration as a CRDT
|
// GetMesh: Gets a nodes local mesh configuration as a CRDT
|
||||||
func (s *SyncServiceImpl) GetConf(context context.Context, request *rpc.GetConfRequest) (*rpc.GetConfReply, error) {
|
func (s *SyncServiceImpl) GetConf(context context.Context, request *rpc.GetConfRequest) (*rpc.GetConfReply, error) {
|
||||||
mesh := s.MeshManager.GetMesh(request.MeshId)
|
mesh := s.Server.MeshManager.GetMesh(request.MeshId)
|
||||||
|
|
||||||
if mesh == nil {
|
if mesh == nil {
|
||||||
return nil, errors.New("mesh does not exist")
|
return nil, errors.New("mesh does not exist")
|
||||||
@ -55,7 +56,7 @@ func (s *SyncServiceImpl) SyncMesh(stream rpc.SyncService_SyncMeshServer) error
|
|||||||
if len(meshId) == 0 {
|
if len(meshId) == 0 {
|
||||||
meshId = in.MeshId
|
meshId = in.MeshId
|
||||||
|
|
||||||
mesh := s.MeshManager.GetMesh(meshId)
|
mesh := s.Server.MeshManager.GetMesh(meshId)
|
||||||
|
|
||||||
if mesh == nil {
|
if mesh == nil {
|
||||||
return errors.New("mesh does not exist")
|
return errors.New("mesh does not exist")
|
||||||
@ -91,3 +92,7 @@ func (s *SyncServiceImpl) SyncMesh(stream rpc.SyncService_SyncMeshServer) error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSyncService(server *ctrlserver.MeshCtrlServer) *SyncServiceImpl {
|
||||||
|
return &SyncServiceImpl{Server: server}
|
||||||
|
}
|
||||||
|
15
pkg/timers/timers.go
Normal file
15
pkg/timers/timers.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package timer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/ctrlserver"
|
||||||
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewTimestampScheduler(ctrlServer *ctrlserver.MeshCtrlServer) lib.Timer {
|
||||||
|
timerFunc := func() error {
|
||||||
|
logging.Log.WriteInfof("Updated Timestamp")
|
||||||
|
return ctrlServer.MeshManager.UpdateTimeStamp()
|
||||||
|
}
|
||||||
|
return *lib.NewTimer(timerFunc, ctrlServer.Conf.KeepAliveTime)
|
||||||
|
}
|
@ -5,8 +5,8 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/tim-beatham/smegmesh/pkg/lib"
|
"github.com/tim-beatham/wgmesh/pkg/lib"
|
||||||
logging "github.com/tim-beatham/smegmesh/pkg/log"
|
logging "github.com/tim-beatham/wgmesh/pkg/log"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl"
|
"golang.zx2c4.com/wireguard/wgctrl"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
)
|
)
|
||||||
|
1
smegmesh-web
Submodule
1
smegmesh-web
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit c1128bcd98a6ce4a04d4fe55c210d115d564419a
|
Loading…
Reference in New Issue
Block a user