Compare commits
128 Commits
0.0.201812
...
0.0.201904
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18fa270472 | ||
|
|
f156a53ff4 | ||
|
|
e680008700 | ||
|
|
767c86f8cb | ||
|
|
421c1f9143 | ||
|
|
ac25702eaf | ||
|
|
92f8474832 | ||
|
|
2e0ed4614a | ||
|
|
2fa80c0cb7 | ||
|
|
52ec440d79 | ||
|
|
2faf2dcf90 | ||
|
|
41c30a7279 | ||
|
|
4b1db1d39b | ||
|
|
a80db5e65e | ||
|
|
9748a52073 | ||
|
|
317d716d66 | ||
|
|
6440f010ee | ||
|
|
49ea0c9b1a | ||
|
|
ca59b60aa7 | ||
|
|
c050c6e60f | ||
|
|
91b4e909bb | ||
|
|
2c51d6af48 | ||
|
|
03f2e2614a | ||
|
|
b0e0ab308d | ||
|
|
66fb5caf02 | ||
|
|
3dd9a0535f | ||
|
|
c2a2b8d739 | ||
|
|
70449f1a97 | ||
|
|
33c3528430 | ||
|
|
30ab07e354 | ||
|
|
a6d5ef82f4 | ||
|
|
5c7cc256e3 | ||
|
|
368dea72fe | ||
|
|
9b22255cad | ||
|
|
11f5780250 | ||
|
|
26af6c4651 | ||
|
|
92f72f5aa6 | ||
|
|
1fdf7b19a3 | ||
|
|
a1aabb21ae | ||
|
|
9041d38e2d | ||
|
|
cddfd9a0d8 | ||
|
|
68f0721c6a | ||
|
|
b8e85267cf | ||
|
|
69f0fe67b6 | ||
|
|
d435be35ca | ||
|
|
967d1a0f3d | ||
|
|
88ff67fb6f | ||
|
|
971be13e77 | ||
|
|
366cbd11a4 | ||
|
|
ab0f442daf | ||
|
|
66524c1f7e | ||
|
|
6e4460ae65 | ||
|
|
d002eff155 | ||
|
|
e06a8f8f9f | ||
|
|
ac4944a708 | ||
|
|
2491f9d454 | ||
|
|
8091c6474a | ||
|
|
040da43889 | ||
|
|
b7025b5627 | ||
|
|
6581cfb885 | ||
|
|
4863089120 | ||
|
|
42c6d0e261 | ||
|
|
f7170e5de2 | ||
|
|
b719a09a26 | ||
|
|
f05f52637f | ||
|
|
713477cfb1 | ||
|
|
5981d5cacf | ||
|
|
b13739ada2 | ||
|
|
c4988999ac | ||
|
|
b662896cf4 | ||
|
|
0525f6b112 | ||
|
|
9d830826c5 | ||
|
|
bd963497da | ||
|
|
05d25fd1b7 | ||
|
|
6d2729dccc | ||
|
|
d87cbeeb2f | ||
|
|
043b7e8013 | ||
|
|
ef48d4fa95 | ||
|
|
f7276ed522 | ||
|
|
c4b43e35a7 | ||
|
|
2efafecab5 | ||
|
|
fac1fbcd72 | ||
|
|
52aa00f3ba | ||
|
|
ea59177f1c | ||
|
|
306d08e692 | ||
|
|
3b7a4fa3ef | ||
|
|
223685875f | ||
|
|
652158ec3c | ||
|
|
cb2bc4b34c | ||
|
|
46279ad0f9 | ||
|
|
73df1c0871 | ||
|
|
069016bbc4 | ||
|
|
3c29434a79 | ||
|
|
c599bf9497 | ||
|
|
f7f63765d1 | ||
|
|
3e8f2e3fa5 | ||
|
|
7b636380e5 | ||
|
|
99a3b628e9 | ||
|
|
e7ffce0d21 | ||
|
|
35f72239ac | ||
|
|
c15cbefc12 | ||
|
|
dd998ca86a | ||
|
|
024a4916c2 | ||
|
|
963be8e993 | ||
|
|
e821cdabd2 | ||
|
|
38c7acd70f | ||
|
|
20f1512b7c | ||
|
|
348b4e9f7c | ||
|
|
f81882ee8b | ||
|
|
3e0e61dd26 | ||
|
|
9635a0b3a6 | ||
|
|
90b6938ca0 | ||
|
|
269944002f | ||
|
|
a5a1ece32f | ||
|
|
f1d5db6547 | ||
|
|
dce5192d86 | ||
|
|
955d8dfe04 | ||
|
|
25e18d01e6 | ||
|
|
45959c116a | ||
|
|
d41bc015cc | ||
|
|
31949136df | ||
|
|
6f76edd045 | ||
|
|
3af9aa88a3 | ||
|
|
a5ca02d79a | ||
|
|
2b7562abbb | ||
|
|
89d2c5ed7a | ||
|
|
dff424baf8 | ||
|
|
6e61c369e8 |
351
COPYING
351
COPYING
@@ -1,338 +1,17 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
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
|
||||
convey 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 version 2
|
||||
as published by the Free Software Foundation.
|
||||
|
||||
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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
8
Makefile
8
Makefile
@@ -24,10 +24,10 @@ MAKEFLAGS += --no-print-directory
|
||||
generate-version-and-build:
|
||||
@export GIT_CEILING_DIRECTORIES="$(realpath $(CURDIR)/..)" && \
|
||||
tag="$$(git describe --dirty 2>/dev/null)" && \
|
||||
ver="$$(printf 'package main\nconst WireGuardGoVersion = "%s"\n' "$$tag")" && \
|
||||
[ "$$(cat version.go 2>/dev/null)" != "$$ver" ] && \
|
||||
echo "$$ver" > version.go && \
|
||||
git update-index --assume-unchanged version.go || true
|
||||
ver="$$(printf 'package device\nconst WireGuardGoVersion = "%s"\n' "$$tag")" && \
|
||||
[ "$$(cat device/version.go 2>/dev/null)" != "$$ver" ] && \
|
||||
echo "$$ver" > device/version.go && \
|
||||
git update-index --assume-unchanged device/version.go || true
|
||||
@$(MAKE) wireguard-go
|
||||
|
||||
wireguard-go: $(wildcard *.go) $(wildcard */*.go)
|
||||
|
||||
39
README.md
39
README.md
@@ -48,7 +48,7 @@ This will run on OpenBSD. It does not yet support sticky sockets. Fwmark is mapp
|
||||
|
||||
## Building
|
||||
|
||||
This requires an installation of [go](https://golang.org) ≥ 1.11.
|
||||
This requires an installation of [go](https://golang.org) ≥ 1.12.
|
||||
|
||||
```
|
||||
$ git clone https://git.zx2c4.com/wireguard-go
|
||||
@@ -58,27 +58,22 @@ $ make
|
||||
|
||||
## License
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation.
|
||||
Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
|
||||
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, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
Additional Permissions For Submission to Apple App Store: Provided that you
|
||||
are otherwise in compliance with the GPLv2 for each covered work you convey
|
||||
(including without limitation making the Corresponding Source available in
|
||||
compliance with Section 3 of the GPLv2), you are granted the additional
|
||||
permission to convey through the Apple App Store non-source executable
|
||||
versions of the Program as incorporated into each applicable covered work
|
||||
as Executable Versions only under the Mozilla Public License version 2.0
|
||||
(https://www.mozilla.org/en-US/MPL/2.0/).
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import "errors"
|
||||
|
||||
34
device/boundif_android.go
Normal file
34
device/boundif_android.go
Normal file
@@ -0,0 +1,34 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package device
|
||||
|
||||
func (device *Device) PeekLookAtSocketFd4() (fd int, err error) {
|
||||
sysconn, err := device.net.bind.(*nativeBind).ipv4.SyscallConn()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = sysconn.Control(func(f uintptr) {
|
||||
fd = int(f)
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (device *Device) PeekLookAtSocketFd6() (fd int, err error) {
|
||||
sysconn, err := device.net.bind.(*nativeBind).ipv6.SyscallConn()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = sysconn.Control(func(f uintptr) {
|
||||
fd = int(f)
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
44
device/boundif_darwin.go
Normal file
44
device/boundif_darwin.go
Normal file
@@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package device
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func (device *Device) BindSocketToInterface4(interfaceIndex uint32) error {
|
||||
sysconn, err := device.net.bind.(*nativeBind).ipv4.SyscallConn()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
err2 := sysconn.Control(func(fd uintptr) {
|
||||
err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_BOUND_IF, int(interfaceIndex))
|
||||
})
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (device *Device) BindSocketToInterface6(interfaceIndex uint32) error {
|
||||
sysconn, err := device.net.bind.(*nativeBind).ipv4.SyscallConn()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
err2 := sysconn.Control(func(fd uintptr) {
|
||||
err = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_BOUND_IF, int(interfaceIndex))
|
||||
})
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
56
device/boundif_windows.go
Normal file
56
device/boundif_windows.go
Normal file
@@ -0,0 +1,56 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package device
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"golang.org/x/sys/windows"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
sockoptIP_UNICAST_IF = 31
|
||||
sockoptIPV6_UNICAST_IF = 31
|
||||
)
|
||||
|
||||
func (device *Device) BindSocketToInterface4(interfaceIndex uint32) error {
|
||||
/* MSDN says for IPv4 this needs to be in net byte order, so that it's like an IP address with leading zeros. */
|
||||
bytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(bytes, interfaceIndex)
|
||||
interfaceIndex = *(*uint32)(unsafe.Pointer(&bytes[0]))
|
||||
|
||||
sysconn, err := device.net.bind.(*nativeBind).ipv4.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err2 := sysconn.Control(func(fd uintptr) {
|
||||
err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, sockoptIP_UNICAST_IF, int(interfaceIndex))
|
||||
})
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (device *Device) BindSocketToInterface6(interfaceIndex uint32) error {
|
||||
sysconn, err := device.net.bind.(*nativeBind).ipv6.SyscallConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err2 := sysconn.Control(func(fd uintptr) {
|
||||
err = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IPV6, sockoptIPV6_UNICAST_IF, int(interfaceIndex))
|
||||
})
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -78,8 +78,8 @@ func unsafeCloseBind(device *Device) error {
|
||||
|
||||
func (device *Device) BindSetMark(mark uint32) error {
|
||||
|
||||
device.net.mutex.Lock()
|
||||
defer device.net.mutex.Unlock()
|
||||
device.net.Lock()
|
||||
defer device.net.Unlock()
|
||||
|
||||
// check if modified
|
||||
|
||||
@@ -98,23 +98,23 @@ func (device *Device) BindSetMark(mark uint32) error {
|
||||
|
||||
// clear cached source addresses
|
||||
|
||||
device.peers.mutex.RLock()
|
||||
device.peers.RLock()
|
||||
for _, peer := range device.peers.keyMap {
|
||||
peer.mutex.Lock()
|
||||
defer peer.mutex.Unlock()
|
||||
peer.Lock()
|
||||
defer peer.Unlock()
|
||||
if peer.endpoint != nil {
|
||||
peer.endpoint.ClearSrc()
|
||||
}
|
||||
}
|
||||
device.peers.mutex.RUnlock()
|
||||
device.peers.RUnlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (device *Device) BindUpdate() error {
|
||||
|
||||
device.net.mutex.Lock()
|
||||
defer device.net.mutex.Unlock()
|
||||
device.net.Lock()
|
||||
defer device.net.Unlock()
|
||||
|
||||
// close existing sockets
|
||||
|
||||
@@ -148,15 +148,15 @@ func (device *Device) BindUpdate() error {
|
||||
|
||||
// clear cached source addresses
|
||||
|
||||
device.peers.mutex.RLock()
|
||||
device.peers.RLock()
|
||||
for _, peer := range device.peers.keyMap {
|
||||
peer.mutex.Lock()
|
||||
defer peer.mutex.Unlock()
|
||||
peer.Lock()
|
||||
defer peer.Unlock()
|
||||
if peer.endpoint != nil {
|
||||
peer.endpoint.ClearSrc()
|
||||
}
|
||||
}
|
||||
device.peers.mutex.RUnlock()
|
||||
device.peers.RUnlock()
|
||||
|
||||
// start receiving routines
|
||||
|
||||
@@ -173,8 +173,8 @@ func (device *Device) BindUpdate() error {
|
||||
}
|
||||
|
||||
func (device *Device) BindClose() error {
|
||||
device.net.mutex.Lock()
|
||||
device.net.Lock()
|
||||
err := unsafeCloseBind(device)
|
||||
device.net.mutex.Unlock()
|
||||
device.net.Unlock()
|
||||
return err
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
// +build !linux android
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"net"
|
||||
@@ -20,14 +20,14 @@ import (
|
||||
* See conn_linux.go for an implementation on the linux platform.
|
||||
*/
|
||||
|
||||
type NativeBind struct {
|
||||
type nativeBind struct {
|
||||
ipv4 *net.UDPConn
|
||||
ipv6 *net.UDPConn
|
||||
}
|
||||
|
||||
type NativeEndpoint net.UDPAddr
|
||||
|
||||
var _ Bind = (*NativeBind)(nil)
|
||||
var _ Bind = (*nativeBind)(nil)
|
||||
var _ Endpoint = (*NativeEndpoint)(nil)
|
||||
|
||||
func CreateEndpoint(s string) (Endpoint, error) {
|
||||
@@ -100,7 +100,7 @@ func extractErrno(err error) error {
|
||||
|
||||
func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
|
||||
var err error
|
||||
var bind NativeBind
|
||||
var bind nativeBind
|
||||
|
||||
port := int(uport)
|
||||
|
||||
@@ -111,7 +111,6 @@ func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
|
||||
|
||||
bind.ipv6, port, err = listenNet("udp6", port)
|
||||
if err != nil && extractErrno(err) != syscall.EAFNOSUPPORT {
|
||||
return nil, 0, err
|
||||
bind.ipv4.Close()
|
||||
bind.ipv4 = nil
|
||||
return nil, 0, err
|
||||
@@ -120,7 +119,7 @@ func CreateBind(uport uint16, device *Device) (Bind, uint16, error) {
|
||||
return &bind, uint16(port), nil
|
||||
}
|
||||
|
||||
func (bind *NativeBind) Close() error {
|
||||
func (bind *nativeBind) Close() error {
|
||||
var err1, err2 error
|
||||
if bind.ipv4 != nil {
|
||||
err1 = bind.ipv4.Close()
|
||||
@@ -134,7 +133,7 @@ func (bind *NativeBind) Close() error {
|
||||
return err2
|
||||
}
|
||||
|
||||
func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
func (bind *nativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
if bind.ipv4 == nil {
|
||||
return 0, nil, syscall.EAFNOSUPPORT
|
||||
}
|
||||
@@ -145,7 +144,7 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
return n, (*NativeEndpoint)(endpoint), err
|
||||
}
|
||||
|
||||
func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
func (bind *nativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
if bind.ipv6 == nil {
|
||||
return 0, nil, syscall.EAFNOSUPPORT
|
||||
}
|
||||
@@ -153,7 +152,7 @@ func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
return n, (*NativeEndpoint)(endpoint), err
|
||||
}
|
||||
|
||||
func (bind *NativeBind) Send(buff []byte, endpoint Endpoint) error {
|
||||
func (bind *nativeBind) Send(buff []byte, endpoint Endpoint) error {
|
||||
var err error
|
||||
nend := endpoint.(*NativeEndpoint)
|
||||
if nend.IP.To4() != nil {
|
||||
@@ -1,8 +1,8 @@
|
||||
// +build !android
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*
|
||||
* This implements userspace semantics of "sticky sockets", modeled after
|
||||
* WireGuard's kernelspace implementation. This is more or less a straight port
|
||||
@@ -14,12 +14,12 @@
|
||||
* So this code is remains platform dependent.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/rwcancel"
|
||||
"net"
|
||||
"strconv"
|
||||
"sync"
|
||||
@@ -63,7 +63,7 @@ func (endpoint *NativeEndpoint) dst6() *unix.SockaddrInet6 {
|
||||
return (*unix.SockaddrInet6)(unsafe.Pointer(&endpoint.dst[0]))
|
||||
}
|
||||
|
||||
type NativeBind struct {
|
||||
type nativeBind struct {
|
||||
sock4 int
|
||||
sock6 int
|
||||
netlinkSock int
|
||||
@@ -72,7 +72,7 @@ type NativeBind struct {
|
||||
}
|
||||
|
||||
var _ Endpoint = (*NativeEndpoint)(nil)
|
||||
var _ Bind = (*NativeBind)(nil)
|
||||
var _ Bind = (*nativeBind)(nil)
|
||||
|
||||
func CreateEndpoint(s string) (Endpoint, error) {
|
||||
var end NativeEndpoint
|
||||
@@ -127,9 +127,9 @@ func createNetlinkRouteSocket() (int, error) {
|
||||
|
||||
}
|
||||
|
||||
func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) {
|
||||
func CreateBind(port uint16, device *Device) (*nativeBind, uint16, error) {
|
||||
var err error
|
||||
var bind NativeBind
|
||||
var bind nativeBind
|
||||
var newPort uint16
|
||||
|
||||
bind.netlinkSock, err = createNetlinkRouteSocket()
|
||||
@@ -176,7 +176,7 @@ func CreateBind(port uint16, device *Device) (*NativeBind, uint16, error) {
|
||||
return &bind, port, nil
|
||||
}
|
||||
|
||||
func (bind *NativeBind) SetMark(value uint32) error {
|
||||
func (bind *nativeBind) SetMark(value uint32) error {
|
||||
if bind.sock6 != -1 {
|
||||
err := unix.SetsockoptInt(
|
||||
bind.sock6,
|
||||
@@ -213,7 +213,7 @@ func closeUnblock(fd int) error {
|
||||
return unix.Close(fd)
|
||||
}
|
||||
|
||||
func (bind *NativeBind) Close() error {
|
||||
func (bind *nativeBind) Close() error {
|
||||
var err1, err2, err3 error
|
||||
if bind.sock6 != -1 {
|
||||
err1 = closeUnblock(bind.sock6)
|
||||
@@ -232,7 +232,7 @@ func (bind *NativeBind) Close() error {
|
||||
return err3
|
||||
}
|
||||
|
||||
func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
func (bind *nativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
var end NativeEndpoint
|
||||
if bind.sock6 == -1 {
|
||||
return 0, nil, syscall.EAFNOSUPPORT
|
||||
@@ -245,7 +245,7 @@ func (bind *NativeBind) ReceiveIPv6(buff []byte) (int, Endpoint, error) {
|
||||
return n, &end, err
|
||||
}
|
||||
|
||||
func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
func (bind *nativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
var end NativeEndpoint
|
||||
if bind.sock4 == -1 {
|
||||
return 0, nil, syscall.EAFNOSUPPORT
|
||||
@@ -258,7 +258,7 @@ func (bind *NativeBind) ReceiveIPv4(buff []byte) (int, Endpoint, error) {
|
||||
return n, &end, err
|
||||
}
|
||||
|
||||
func (bind *NativeBind) Send(buff []byte, end Endpoint) error {
|
||||
func (bind *nativeBind) Send(buff []byte, end Endpoint) error {
|
||||
nend := end.(*NativeEndpoint)
|
||||
if !nend.isV6 {
|
||||
if bind.sock4 == -1 {
|
||||
@@ -592,7 +592,7 @@ func receive6(sock int, buff []byte, end *NativeEndpoint) (int, error) {
|
||||
return size, nil
|
||||
}
|
||||
|
||||
func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
func (bind *nativeBind) routineRouteListener(device *Device) {
|
||||
type peerEndpointPtr struct {
|
||||
peer *Peer
|
||||
endpoint *Endpoint
|
||||
@@ -654,17 +654,17 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
pePtr.peer.mutex.Lock()
|
||||
pePtr.peer.Lock()
|
||||
if &pePtr.peer.endpoint != pePtr.endpoint {
|
||||
pePtr.peer.mutex.Unlock()
|
||||
pePtr.peer.Unlock()
|
||||
break
|
||||
}
|
||||
if uint32(pePtr.peer.endpoint.(*NativeEndpoint).src4().ifindex) == ifidx {
|
||||
pePtr.peer.mutex.Unlock()
|
||||
pePtr.peer.Unlock()
|
||||
break
|
||||
}
|
||||
pePtr.peer.endpoint.(*NativeEndpoint).ClearSrc()
|
||||
pePtr.peer.mutex.Unlock()
|
||||
pePtr.peer.Unlock()
|
||||
}
|
||||
attr = attr[attrhdr.Len:]
|
||||
}
|
||||
@@ -675,16 +675,16 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
reqPeer = make(map[uint32]peerEndpointPtr)
|
||||
reqPeerLock.Unlock()
|
||||
go func() {
|
||||
device.peers.mutex.RLock()
|
||||
device.peers.RLock()
|
||||
i := uint32(1)
|
||||
for _, peer := range device.peers.keyMap {
|
||||
peer.mutex.RLock()
|
||||
peer.RLock()
|
||||
if peer.endpoint == nil || peer.endpoint.(*NativeEndpoint) == nil {
|
||||
peer.mutex.RUnlock()
|
||||
peer.RUnlock()
|
||||
continue
|
||||
}
|
||||
if peer.endpoint.(*NativeEndpoint).isV6 || peer.endpoint.(*NativeEndpoint).src4().ifindex == 0 {
|
||||
peer.mutex.RUnlock()
|
||||
peer.RUnlock()
|
||||
break
|
||||
}
|
||||
nlmsg := struct {
|
||||
@@ -730,14 +730,14 @@ func (bind *NativeBind) routineRouteListener(device *Device) {
|
||||
endpoint: &peer.endpoint,
|
||||
}
|
||||
reqPeerLock.Unlock()
|
||||
peer.mutex.RUnlock()
|
||||
peer.RUnlock()
|
||||
i++
|
||||
_, err := bind.netlinkCancel.Write((*[unsafe.Sizeof(nlmsg)]byte)(unsafe.Pointer(&nlmsg))[:])
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
device.peers.mutex.RUnlock()
|
||||
device.peers.RUnlock()
|
||||
}()
|
||||
}
|
||||
remain = remain[hdr.Len:]
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"time"
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
)
|
||||
|
||||
type CookieChecker struct {
|
||||
mutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
mac1 struct {
|
||||
key [blake2s.Size]byte
|
||||
}
|
||||
@@ -27,7 +27,7 @@ type CookieChecker struct {
|
||||
}
|
||||
|
||||
type CookieGenerator struct {
|
||||
mutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
mac1 struct {
|
||||
key [blake2s.Size]byte
|
||||
}
|
||||
@@ -41,8 +41,8 @@ type CookieGenerator struct {
|
||||
}
|
||||
|
||||
func (st *CookieChecker) Init(pk NoisePublicKey) {
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
st.Lock()
|
||||
defer st.Unlock()
|
||||
|
||||
// mac1 state
|
||||
|
||||
@@ -66,8 +66,8 @@ func (st *CookieChecker) Init(pk NoisePublicKey) {
|
||||
}
|
||||
|
||||
func (st *CookieChecker) CheckMAC1(msg []byte) bool {
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
st.RLock()
|
||||
defer st.RUnlock()
|
||||
|
||||
size := len(msg)
|
||||
smac2 := size - blake2s.Size128
|
||||
@@ -83,8 +83,8 @@ func (st *CookieChecker) CheckMAC1(msg []byte) bool {
|
||||
}
|
||||
|
||||
func (st *CookieChecker) CheckMAC2(msg []byte, src []byte) bool {
|
||||
st.mutex.RLock()
|
||||
defer st.mutex.RUnlock()
|
||||
st.RLock()
|
||||
defer st.RUnlock()
|
||||
|
||||
if time.Now().Sub(st.mac2.secretSet) > CookieRefreshTime {
|
||||
return false
|
||||
@@ -119,21 +119,21 @@ func (st *CookieChecker) CreateReply(
|
||||
src []byte,
|
||||
) (*MessageCookieReply, error) {
|
||||
|
||||
st.mutex.RLock()
|
||||
st.RLock()
|
||||
|
||||
// refresh cookie secret
|
||||
|
||||
if time.Now().Sub(st.mac2.secretSet) > CookieRefreshTime {
|
||||
st.mutex.RUnlock()
|
||||
st.mutex.Lock()
|
||||
st.RUnlock()
|
||||
st.Lock()
|
||||
_, err := rand.Read(st.mac2.secret[:])
|
||||
if err != nil {
|
||||
st.mutex.Unlock()
|
||||
st.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
st.mac2.secretSet = time.Now()
|
||||
st.mutex.Unlock()
|
||||
st.mutex.RLock()
|
||||
st.Unlock()
|
||||
st.RLock()
|
||||
}
|
||||
|
||||
// derive cookie
|
||||
@@ -158,21 +158,21 @@ func (st *CookieChecker) CreateReply(
|
||||
|
||||
_, err := rand.Read(reply.Nonce[:])
|
||||
if err != nil {
|
||||
st.mutex.RUnlock()
|
||||
st.RUnlock()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
xchapoly, _ := chacha20poly1305.NewX(st.mac2.encryptionKey[:])
|
||||
xchapoly.Seal(reply.Cookie[:0], reply.Nonce[:], cookie[:], msg[smac1:smac2])
|
||||
|
||||
st.mutex.RUnlock()
|
||||
st.RUnlock()
|
||||
|
||||
return reply, nil
|
||||
}
|
||||
|
||||
func (st *CookieGenerator) Init(pk NoisePublicKey) {
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
st.Lock()
|
||||
defer st.Unlock()
|
||||
|
||||
func() {
|
||||
hash, _ := blake2s.New256(nil)
|
||||
@@ -192,8 +192,8 @@ func (st *CookieGenerator) Init(pk NoisePublicKey) {
|
||||
}
|
||||
|
||||
func (st *CookieGenerator) ConsumeReply(msg *MessageCookieReply) bool {
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
st.Lock()
|
||||
defer st.Unlock()
|
||||
|
||||
if !st.mac2.hasLastMAC1 {
|
||||
return false
|
||||
@@ -223,8 +223,8 @@ func (st *CookieGenerator) AddMacs(msg []byte) {
|
||||
mac1 := msg[smac1:smac2]
|
||||
mac2 := msg[smac2:]
|
||||
|
||||
st.mutex.Lock()
|
||||
defer st.mutex.Unlock()
|
||||
st.Lock()
|
||||
defer st.Unlock()
|
||||
|
||||
// set mac1
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"testing"
|
||||
@@ -1,13 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"git.zx2c4.com/wireguard-go/ratelimiter"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"golang.zx2c4.com/wireguard/ratelimiter"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -29,7 +29,7 @@ type Device struct {
|
||||
state struct {
|
||||
starting sync.WaitGroup
|
||||
stopping sync.WaitGroup
|
||||
mutex sync.Mutex
|
||||
sync.Mutex
|
||||
changing AtomicBool
|
||||
current bool
|
||||
}
|
||||
@@ -37,20 +37,20 @@ type Device struct {
|
||||
net struct {
|
||||
starting sync.WaitGroup
|
||||
stopping sync.WaitGroup
|
||||
mutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
bind Bind // bind interface
|
||||
port uint16 // listening port
|
||||
fwmark uint32 // mark value (0 = disabled)
|
||||
}
|
||||
|
||||
staticIdentity struct {
|
||||
mutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
privateKey NoisePrivateKey
|
||||
publicKey NoisePublicKey
|
||||
}
|
||||
|
||||
peers struct {
|
||||
mutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
keyMap map[NoisePublicKey]*Peer
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ type Device struct {
|
||||
/* Converts the peer into a "zombie", which remains in the peer map,
|
||||
* but processes no packets and does not exists in the routing table.
|
||||
*
|
||||
* Must hold device.peers.mutex.
|
||||
* Must hold device.peers.Mutex
|
||||
*/
|
||||
func unsafeRemovePeer(device *Device, peer *Peer, key NoisePublicKey) {
|
||||
|
||||
@@ -117,13 +117,13 @@ func deviceUpdateState(device *Device) {
|
||||
|
||||
// compare to current state of device
|
||||
|
||||
device.state.mutex.Lock()
|
||||
device.state.Lock()
|
||||
|
||||
newIsUp := device.isUp.Get()
|
||||
|
||||
if newIsUp == device.state.current {
|
||||
device.state.changing.Set(false)
|
||||
device.state.mutex.Unlock()
|
||||
device.state.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -135,26 +135,29 @@ func deviceUpdateState(device *Device) {
|
||||
device.isUp.Set(false)
|
||||
break
|
||||
}
|
||||
device.peers.mutex.RLock()
|
||||
device.peers.RLock()
|
||||
for _, peer := range device.peers.keyMap {
|
||||
peer.Start()
|
||||
if peer.persistentKeepaliveInterval > 0 {
|
||||
peer.SendKeepalive()
|
||||
}
|
||||
device.peers.mutex.RUnlock()
|
||||
}
|
||||
device.peers.RUnlock()
|
||||
|
||||
case false:
|
||||
device.BindClose()
|
||||
device.peers.mutex.RLock()
|
||||
device.peers.RLock()
|
||||
for _, peer := range device.peers.keyMap {
|
||||
peer.Stop()
|
||||
}
|
||||
device.peers.mutex.RUnlock()
|
||||
device.peers.RUnlock()
|
||||
}
|
||||
|
||||
// update state variables
|
||||
|
||||
device.state.current = newIsUp
|
||||
device.state.changing.Set(false)
|
||||
device.state.mutex.Unlock()
|
||||
device.state.Unlock()
|
||||
|
||||
// check for state change in the mean time
|
||||
|
||||
@@ -199,11 +202,11 @@ func (device *Device) SetPrivateKey(sk NoisePrivateKey) error {
|
||||
|
||||
// lock required resources
|
||||
|
||||
device.staticIdentity.mutex.Lock()
|
||||
defer device.staticIdentity.mutex.Unlock()
|
||||
device.staticIdentity.Lock()
|
||||
defer device.staticIdentity.Unlock()
|
||||
|
||||
device.peers.mutex.Lock()
|
||||
defer device.peers.mutex.Unlock()
|
||||
device.peers.Lock()
|
||||
defer device.peers.Unlock()
|
||||
|
||||
for _, peer := range device.peers.keyMap {
|
||||
peer.handshake.mutex.RLock()
|
||||
@@ -310,15 +313,15 @@ func NewDevice(tunDevice tun.TUNDevice, logger *Logger) *Device {
|
||||
}
|
||||
|
||||
func (device *Device) LookupPeer(pk NoisePublicKey) *Peer {
|
||||
device.peers.mutex.RLock()
|
||||
defer device.peers.mutex.RUnlock()
|
||||
device.peers.RLock()
|
||||
defer device.peers.RUnlock()
|
||||
|
||||
return device.peers.keyMap[pk]
|
||||
}
|
||||
|
||||
func (device *Device) RemovePeer(key NoisePublicKey) {
|
||||
device.peers.mutex.Lock()
|
||||
defer device.peers.mutex.Unlock()
|
||||
device.peers.Lock()
|
||||
defer device.peers.Unlock()
|
||||
|
||||
// stop peer and remove from routing
|
||||
|
||||
@@ -329,8 +332,8 @@ func (device *Device) RemovePeer(key NoisePublicKey) {
|
||||
}
|
||||
|
||||
func (device *Device) RemoveAllPeers() {
|
||||
device.peers.mutex.Lock()
|
||||
defer device.peers.mutex.Unlock()
|
||||
device.peers.Lock()
|
||||
defer device.peers.Unlock()
|
||||
|
||||
for key, peer := range device.peers.keyMap {
|
||||
unsafeRemovePeer(device, peer, key)
|
||||
@@ -367,8 +370,8 @@ func (device *Device) Close() {
|
||||
|
||||
device.log.Info.Println("Device closing")
|
||||
device.state.changing.Set(true)
|
||||
device.state.mutex.Lock()
|
||||
defer device.state.mutex.Unlock()
|
||||
device.state.Lock()
|
||||
defer device.state.Unlock()
|
||||
|
||||
device.tun.device.Close()
|
||||
device.BindClose()
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
/* Create two device instances and simulate full WireGuard interaction
|
||||
* without network dependencies
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
@@ -18,7 +18,7 @@ type IndexTableEntry struct {
|
||||
}
|
||||
|
||||
type IndexTable struct {
|
||||
mutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
table map[uint32]IndexTableEntry
|
||||
}
|
||||
|
||||
@@ -29,20 +29,20 @@ func randUint32() (uint32, error) {
|
||||
}
|
||||
|
||||
func (table *IndexTable) Init() {
|
||||
table.mutex.Lock()
|
||||
defer table.mutex.Unlock()
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
table.table = make(map[uint32]IndexTableEntry)
|
||||
}
|
||||
|
||||
func (table *IndexTable) Delete(index uint32) {
|
||||
table.mutex.Lock()
|
||||
defer table.mutex.Unlock()
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
delete(table.table, index)
|
||||
}
|
||||
|
||||
func (table *IndexTable) SwapIndexForKeypair(index uint32, keypair *Keypair) {
|
||||
table.mutex.Lock()
|
||||
defer table.mutex.Unlock()
|
||||
table.Lock()
|
||||
defer table.Unlock()
|
||||
entry, ok := table.table[index]
|
||||
if !ok {
|
||||
return
|
||||
@@ -65,19 +65,19 @@ func (table *IndexTable) NewIndexForHandshake(peer *Peer, handshake *Handshake)
|
||||
|
||||
// check if index used
|
||||
|
||||
table.mutex.RLock()
|
||||
table.RLock()
|
||||
_, ok := table.table[index]
|
||||
table.mutex.RUnlock()
|
||||
table.RUnlock()
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// check again while locked
|
||||
|
||||
table.mutex.Lock()
|
||||
table.Lock()
|
||||
_, found := table.table[index]
|
||||
if found {
|
||||
table.mutex.Unlock()
|
||||
table.Unlock()
|
||||
continue
|
||||
}
|
||||
table.table[index] = IndexTableEntry{
|
||||
@@ -85,13 +85,13 @@ func (table *IndexTable) NewIndexForHandshake(peer *Peer, handshake *Handshake)
|
||||
handshake: handshake,
|
||||
keypair: nil,
|
||||
}
|
||||
table.mutex.Unlock()
|
||||
table.Unlock()
|
||||
return index, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (table *IndexTable) Lookup(id uint32) IndexTableEntry {
|
||||
table.mutex.RLock()
|
||||
defer table.mutex.RUnlock()
|
||||
table.RLock()
|
||||
defer table.RUnlock()
|
||||
return table.table[id]
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"net"
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
@@ -1,13 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"git.zx2c4.com/wireguard-go/replay"
|
||||
"golang.zx2c4.com/wireguard/replay"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -31,15 +31,15 @@ type Keypair struct {
|
||||
}
|
||||
|
||||
type Keypairs struct {
|
||||
mutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
current *Keypair
|
||||
previous *Keypair
|
||||
next *Keypair
|
||||
}
|
||||
|
||||
func (kp *Keypairs) Current() *Keypair {
|
||||
kp.mutex.RLock()
|
||||
defer kp.mutex.RUnlock()
|
||||
kp.RLock()
|
||||
defer kp.RUnlock()
|
||||
return kp.current
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"io"
|
||||
12
device/mark_default.go
Normal file
12
device/mark_default.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// +build !linux,!openbsd,!freebsd
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package device
|
||||
|
||||
func (bind *nativeBind) SetMark(mark uint32) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
// +build android openbsd freebsd
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
@@ -25,7 +25,8 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func (bind *NativeBind) SetMark(mark uint32) error {
|
||||
func (bind *nativeBind) SetMark(mark uint32) error {
|
||||
var operr error
|
||||
if fwmarkIoctl == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -35,8 +36,11 @@ func (bind *NativeBind) SetMark(mark uint32) error {
|
||||
return err
|
||||
}
|
||||
err = fd.Control(func(fd uintptr) {
|
||||
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
|
||||
operr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
|
||||
})
|
||||
if err == nil {
|
||||
err = operr
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -47,8 +51,11 @@ func (bind *NativeBind) SetMark(mark uint32) error {
|
||||
return err
|
||||
}
|
||||
err = fd.Control(func(fd uintptr) {
|
||||
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
|
||||
operr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, fwmarkIoctl, int(mark))
|
||||
})
|
||||
if err == nil {
|
||||
err = operr
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
@@ -17,11 +17,11 @@ const (
|
||||
)
|
||||
|
||||
type AtomicBool struct {
|
||||
flag int32
|
||||
int32
|
||||
}
|
||||
|
||||
func (a *AtomicBool) Get() bool {
|
||||
return atomic.LoadInt32(&a.flag) == AtomicTrue
|
||||
return atomic.LoadInt32(&a.int32) == AtomicTrue
|
||||
}
|
||||
|
||||
func (a *AtomicBool) Swap(val bool) bool {
|
||||
@@ -29,7 +29,7 @@ func (a *AtomicBool) Swap(val bool) bool {
|
||||
if val {
|
||||
flag = AtomicTrue
|
||||
}
|
||||
return atomic.SwapInt32(&a.flag, flag) == AtomicTrue
|
||||
return atomic.SwapInt32(&a.int32, flag) == AtomicTrue
|
||||
}
|
||||
|
||||
func (a *AtomicBool) Set(val bool) {
|
||||
@@ -37,7 +37,7 @@ func (a *AtomicBool) Set(val bool) {
|
||||
if val {
|
||||
flag = AtomicTrue
|
||||
}
|
||||
atomic.StoreInt32(&a.flag, flag)
|
||||
atomic.StoreInt32(&a.int32, flag)
|
||||
}
|
||||
|
||||
func min(a, b uint) uint {
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
@@ -78,12 +78,14 @@ func setZero(arr []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func newPrivateKey() (sk NoisePrivateKey, err error) {
|
||||
// clamping: https://cr.yp.to/ecdh.html
|
||||
_, err = rand.Read(sk[:])
|
||||
func (sk *NoisePrivateKey) clamp() {
|
||||
sk[0] &= 248
|
||||
sk[31] &= 127
|
||||
sk[31] |= 64
|
||||
sk[31] = (sk[31] & 127) | 64
|
||||
}
|
||||
|
||||
func newPrivateKey() (sk NoisePrivateKey, err error) {
|
||||
_, err = rand.Read(sk[:])
|
||||
sk.clamp()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.zx2c4.com/wireguard-go/tai64n"
|
||||
"golang.org/x/crypto/blake2s"
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
"golang.org/x/crypto/poly1305"
|
||||
"golang.zx2c4.com/wireguard/tai64n"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -154,8 +154,8 @@ func init() {
|
||||
|
||||
func (device *Device) CreateMessageInitiation(peer *Peer) (*MessageInitiation, error) {
|
||||
|
||||
device.staticIdentity.mutex.RLock()
|
||||
defer device.staticIdentity.mutex.RUnlock()
|
||||
device.staticIdentity.RLock()
|
||||
defer device.staticIdentity.RUnlock()
|
||||
|
||||
handshake := &peer.handshake
|
||||
handshake.mutex.Lock()
|
||||
@@ -241,8 +241,8 @@ func (device *Device) ConsumeMessageInitiation(msg *MessageInitiation) *Peer {
|
||||
return nil
|
||||
}
|
||||
|
||||
device.staticIdentity.mutex.RLock()
|
||||
defer device.staticIdentity.mutex.RUnlock()
|
||||
device.staticIdentity.RLock()
|
||||
defer device.staticIdentity.RUnlock()
|
||||
|
||||
mixHash(&hash, &InitialHash, device.staticIdentity.publicKey[:])
|
||||
mixHash(&hash, &hash, msg.Ephemeral[:])
|
||||
@@ -423,8 +423,8 @@ func (device *Device) ConsumeMessageResponse(msg *MessageResponse) *Peer {
|
||||
|
||||
// lock private key for reading
|
||||
|
||||
device.staticIdentity.mutex.RLock()
|
||||
defer device.staticIdentity.mutex.RUnlock()
|
||||
device.staticIdentity.RLock()
|
||||
defer device.staticIdentity.RUnlock()
|
||||
|
||||
// finish 3-way DH
|
||||
|
||||
@@ -554,8 +554,8 @@ func (peer *Peer) BeginSymmetricSession() error {
|
||||
// rotate key pairs
|
||||
|
||||
keypairs := &peer.keypairs
|
||||
keypairs.mutex.Lock()
|
||||
defer keypairs.mutex.Unlock()
|
||||
keypairs.Lock()
|
||||
defer keypairs.Unlock()
|
||||
|
||||
previous := keypairs.previous
|
||||
next := keypairs.next
|
||||
@@ -586,8 +586,8 @@ func (peer *Peer) ReceivedWithKeypair(receivedKeypair *Keypair) bool {
|
||||
if keypairs.next != receivedKeypair {
|
||||
return false
|
||||
}
|
||||
keypairs.mutex.Lock()
|
||||
defer keypairs.mutex.Unlock()
|
||||
keypairs.Lock()
|
||||
defer keypairs.Unlock()
|
||||
if keypairs.next != receivedKeypair {
|
||||
return false
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
@@ -45,8 +45,10 @@ func (key NoisePrivateKey) Equals(tar NoisePrivateKey) bool {
|
||||
return subtle.ConstantTimeCompare(key[:], tar[:]) == 1
|
||||
}
|
||||
|
||||
func (key *NoisePrivateKey) FromHex(src string) error {
|
||||
return loadExactHex(key[:], src)
|
||||
func (key *NoisePrivateKey) FromHex(src string) (err error) {
|
||||
err = loadExactHex(key[:], src)
|
||||
key.clamp()
|
||||
return
|
||||
}
|
||||
|
||||
func (key NoisePrivateKey) ToHex() string {
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
@@ -19,7 +19,7 @@ const (
|
||||
|
||||
type Peer struct {
|
||||
isRunning AtomicBool
|
||||
mutex sync.RWMutex // Mostly protects endpoint, but is generally taken whenever we modify peer
|
||||
sync.RWMutex // Mostly protects endpoint, but is generally taken whenever we modify peer
|
||||
keypairs Keypairs
|
||||
handshake Handshake
|
||||
device *Device
|
||||
@@ -57,7 +57,7 @@ type Peer struct {
|
||||
}
|
||||
|
||||
routines struct {
|
||||
mutex sync.Mutex // held when stopping / starting routines
|
||||
sync.Mutex // held when stopping / starting routines
|
||||
starting sync.WaitGroup // routines pending start
|
||||
stopping sync.WaitGroup // routines pending stop
|
||||
stop chan struct{} // size 0, stop all go routines in peer
|
||||
@@ -74,11 +74,11 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
|
||||
|
||||
// lock resources
|
||||
|
||||
device.staticIdentity.mutex.RLock()
|
||||
defer device.staticIdentity.mutex.RUnlock()
|
||||
device.staticIdentity.RLock()
|
||||
defer device.staticIdentity.RUnlock()
|
||||
|
||||
device.peers.mutex.Lock()
|
||||
defer device.peers.mutex.Unlock()
|
||||
device.peers.Lock()
|
||||
defer device.peers.Unlock()
|
||||
|
||||
// check if over limit
|
||||
|
||||
@@ -89,8 +89,8 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
|
||||
// create peer
|
||||
|
||||
peer := new(Peer)
|
||||
peer.mutex.Lock()
|
||||
defer peer.mutex.Unlock()
|
||||
peer.Lock()
|
||||
defer peer.Unlock()
|
||||
|
||||
peer.cookieGenerator.Init(pk)
|
||||
peer.device = device
|
||||
@@ -126,15 +126,15 @@ func (device *Device) NewPeer(pk NoisePublicKey) (*Peer, error) {
|
||||
}
|
||||
|
||||
func (peer *Peer) SendBuffer(buffer []byte) error {
|
||||
peer.device.net.mutex.RLock()
|
||||
defer peer.device.net.mutex.RUnlock()
|
||||
peer.device.net.RLock()
|
||||
defer peer.device.net.RUnlock()
|
||||
|
||||
if peer.device.net.bind == nil {
|
||||
return errors.New("no bind")
|
||||
}
|
||||
|
||||
peer.mutex.RLock()
|
||||
defer peer.mutex.RUnlock()
|
||||
peer.RLock()
|
||||
defer peer.RUnlock()
|
||||
|
||||
if peer.endpoint == nil {
|
||||
return errors.New("no known endpoint for peer")
|
||||
@@ -162,8 +162,8 @@ func (peer *Peer) Start() {
|
||||
|
||||
// prevent simultaneous start/stop operations
|
||||
|
||||
peer.routines.mutex.Lock()
|
||||
defer peer.routines.mutex.Unlock()
|
||||
peer.routines.Lock()
|
||||
defer peer.routines.Unlock()
|
||||
|
||||
if peer.isRunning.Get() {
|
||||
return
|
||||
@@ -207,14 +207,14 @@ func (peer *Peer) ZeroAndFlushAll() {
|
||||
// clear key pairs
|
||||
|
||||
keypairs := &peer.keypairs
|
||||
keypairs.mutex.Lock()
|
||||
keypairs.Lock()
|
||||
device.DeleteKeypair(keypairs.previous)
|
||||
device.DeleteKeypair(keypairs.current)
|
||||
device.DeleteKeypair(keypairs.next)
|
||||
keypairs.previous = nil
|
||||
keypairs.current = nil
|
||||
keypairs.next = nil
|
||||
keypairs.mutex.Unlock()
|
||||
keypairs.Unlock()
|
||||
|
||||
// clear handshake state
|
||||
|
||||
@@ -237,8 +237,8 @@ func (peer *Peer) Stop() {
|
||||
|
||||
peer.routines.starting.Wait()
|
||||
|
||||
peer.routines.mutex.Lock()
|
||||
defer peer.routines.mutex.Unlock()
|
||||
peer.routines.Lock()
|
||||
defer peer.routines.Unlock()
|
||||
|
||||
peer.device.log.Debug.Println(peer, "- Stopping...")
|
||||
|
||||
@@ -258,13 +258,13 @@ func (peer *Peer) Stop() {
|
||||
peer.ZeroAndFlushAll()
|
||||
}
|
||||
|
||||
var roamingDisabled bool
|
||||
var RoamingDisabled bool
|
||||
|
||||
func (peer *Peer) SetEndpointFromPacket(endpoint Endpoint) {
|
||||
if roamingDisabled {
|
||||
if RoamingDisabled {
|
||||
return
|
||||
}
|
||||
peer.mutex.Lock()
|
||||
peer.Lock()
|
||||
peer.endpoint = endpoint
|
||||
peer.mutex.Unlock()
|
||||
peer.Unlock()
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import "sync"
|
||||
|
||||
16
device/queueconstants_android.go
Normal file
16
device/queueconstants_android.go
Normal file
@@ -0,0 +1,16 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package device
|
||||
|
||||
/* Reduce memory consumption for Android */
|
||||
|
||||
const (
|
||||
QueueOutboundSize = 1024
|
||||
QueueInboundSize = 1024
|
||||
QueueHandshakeSize = 1024
|
||||
MaxSegmentSize = 2200
|
||||
PreallocatedBuffersPerPool = 4096
|
||||
)
|
||||
@@ -1,11 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
// +build !android,!ios
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
/* Implementation specific constants */
|
||||
package device
|
||||
|
||||
const (
|
||||
QueueOutboundSize = 1024
|
||||
18
device/queueconstants_ios.go
Normal file
18
device/queueconstants_ios.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// +build ios
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package device
|
||||
|
||||
/* Fit within memory limits for iOS's Network Extension API, which has stricter requirements */
|
||||
|
||||
const (
|
||||
QueueOutboundSize = 1024
|
||||
QueueInboundSize = 1024
|
||||
QueueHandshakeSize = 1024
|
||||
MaxSegmentSize = 1700
|
||||
PreallocatedBuffersPerPool = 1024
|
||||
)
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -27,7 +27,7 @@ type QueueHandshakeElement struct {
|
||||
|
||||
type QueueInboundElement struct {
|
||||
dropped int32
|
||||
mutex sync.Mutex
|
||||
sync.Mutex
|
||||
buffer *[MaxMessageSize]byte
|
||||
packet []byte
|
||||
counter uint64
|
||||
@@ -51,7 +51,7 @@ func (device *Device) addToInboundAndDecryptionQueues(inboundQueue chan *QueueIn
|
||||
return true
|
||||
default:
|
||||
element.Drop()
|
||||
element.mutex.Unlock()
|
||||
element.Unlock()
|
||||
return false
|
||||
}
|
||||
default:
|
||||
@@ -177,8 +177,8 @@ func (device *Device) RoutineReceiveIncoming(IP int, bind Bind) {
|
||||
elem.dropped = AtomicFalse
|
||||
elem.endpoint = endpoint
|
||||
elem.counter = 0
|
||||
elem.mutex = sync.Mutex{}
|
||||
elem.mutex.Lock()
|
||||
elem.Mutex = sync.Mutex{}
|
||||
elem.Lock()
|
||||
|
||||
// add to decryption queues
|
||||
|
||||
@@ -281,7 +281,7 @@ func (device *Device) RoutineDecryption() {
|
||||
elem.Drop()
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
}
|
||||
elem.mutex.Unlock()
|
||||
elem.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -482,6 +482,33 @@ func (device *Device) RoutineHandshake() {
|
||||
}
|
||||
}
|
||||
|
||||
func (peer *Peer) elementStopOrFlush(shouldFlush *bool) (stop bool, elemOk bool, elem *QueueInboundElement) {
|
||||
if !*shouldFlush {
|
||||
select {
|
||||
case <-peer.routines.stop:
|
||||
stop = true
|
||||
return
|
||||
case elem, elemOk = <-peer.queue.inbound:
|
||||
return
|
||||
}
|
||||
} else {
|
||||
select {
|
||||
case <-peer.routines.stop:
|
||||
stop = true
|
||||
return
|
||||
case elem, elemOk = <-peer.queue.inbound:
|
||||
return
|
||||
default:
|
||||
*shouldFlush = false
|
||||
err := peer.device.tun.device.Flush()
|
||||
if err != nil {
|
||||
peer.device.log.Error.Printf("Unable to flush packets: %v", err)
|
||||
}
|
||||
return peer.elementStopOrFlush(shouldFlush)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (peer *Peer) RoutineSequentialReceiver() {
|
||||
|
||||
device := peer.device
|
||||
@@ -491,6 +518,9 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||
|
||||
var elem *QueueInboundElement
|
||||
var ok bool
|
||||
var stop bool
|
||||
|
||||
shouldFlush := false
|
||||
|
||||
defer func() {
|
||||
logDebug.Println(peer, "- Routine: sequential receiver - stopped")
|
||||
@@ -516,20 +546,14 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||
elem = nil
|
||||
}
|
||||
|
||||
select {
|
||||
|
||||
case <-peer.routines.stop:
|
||||
return
|
||||
|
||||
case elem, ok = <-peer.queue.inbound:
|
||||
|
||||
if !ok {
|
||||
stop, ok, elem = peer.elementStopOrFlush(&shouldFlush)
|
||||
if stop || !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// wait for decryption
|
||||
|
||||
elem.mutex.Lock()
|
||||
elem.Lock()
|
||||
|
||||
if elem.IsDropped() {
|
||||
continue
|
||||
@@ -633,9 +657,11 @@ func (peer *Peer) RoutineSequentialReceiver() {
|
||||
offset := MessageTransportOffsetContent
|
||||
atomic.AddUint64(&peer.stats.rxBytes, uint64(len(elem.packet)))
|
||||
_, err := device.tun.device.Write(elem.buffer[:offset+len(elem.packet)], offset)
|
||||
if err != nil {
|
||||
if err == nil {
|
||||
shouldFlush = true
|
||||
}
|
||||
if err != nil && !device.isClosed.Get() {
|
||||
logError.Println("Failed to write packet to TUN device:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -43,7 +43,7 @@ import (
|
||||
|
||||
type QueueOutboundElement struct {
|
||||
dropped int32
|
||||
mutex sync.Mutex
|
||||
sync.Mutex
|
||||
buffer *[MaxMessageSize]byte // slice holding the packet data
|
||||
packet []byte // slice of "buffer" (always!)
|
||||
nonce uint64 // nonce for encryption
|
||||
@@ -55,7 +55,7 @@ func (device *Device) NewOutboundElement() *QueueOutboundElement {
|
||||
elem := device.GetOutboundElement()
|
||||
elem.dropped = AtomicFalse
|
||||
elem.buffer = device.GetMessageBuffer()
|
||||
elem.mutex = sync.Mutex{}
|
||||
elem.Mutex = sync.Mutex{}
|
||||
elem.nonce = 0
|
||||
elem.keypair = nil
|
||||
elem.peer = nil
|
||||
@@ -95,7 +95,7 @@ func addToOutboundAndEncryptionQueues(outboundQueue chan *QueueOutboundElement,
|
||||
default:
|
||||
element.Drop()
|
||||
element.peer.device.PutMessageBuffer(element.buffer)
|
||||
element.mutex.Unlock()
|
||||
element.Unlock()
|
||||
}
|
||||
default:
|
||||
element.peer.device.PutMessageBuffer(element.buffer)
|
||||
@@ -442,7 +442,7 @@ func (peer *Peer) RoutineNonce() {
|
||||
|
||||
elem.keypair = keypair
|
||||
elem.dropped = AtomicFalse
|
||||
elem.mutex.Lock()
|
||||
elem.Lock()
|
||||
|
||||
// add to parallel and sequential queue
|
||||
addToOutboundAndEncryptionQueues(peer.queue.outbound, device.queue.encryption, elem)
|
||||
@@ -468,7 +468,7 @@ func (device *Device) RoutineEncryption() {
|
||||
if ok && !elem.IsDropped() {
|
||||
elem.Drop()
|
||||
device.PutMessageBuffer(elem.buffer)
|
||||
elem.mutex.Unlock()
|
||||
elem.Unlock()
|
||||
}
|
||||
default:
|
||||
goto out
|
||||
@@ -535,7 +535,7 @@ func (device *Device) RoutineEncryption() {
|
||||
elem.packet,
|
||||
nil,
|
||||
)
|
||||
elem.mutex.Unlock()
|
||||
elem.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -588,7 +588,7 @@ func (peer *Peer) RoutineSequentialSender() {
|
||||
return
|
||||
}
|
||||
|
||||
elem.mutex.Lock()
|
||||
elem.Lock()
|
||||
if elem.IsDropped() {
|
||||
device.PutOutboundElement(elem)
|
||||
continue
|
||||
@@ -1,11 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*
|
||||
* This is based heavily on timers.c from the kernel implementation.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
*/
|
||||
|
||||
type Timer struct {
|
||||
timer *time.Timer
|
||||
*time.Timer
|
||||
modifyingLock sync.RWMutex
|
||||
runningLock sync.Mutex
|
||||
isPending bool
|
||||
@@ -27,7 +27,7 @@ type Timer struct {
|
||||
|
||||
func (peer *Peer) NewTimer(expirationFunction func(*Peer)) *Timer {
|
||||
timer := &Timer{}
|
||||
timer.timer = time.AfterFunc(time.Hour, func() {
|
||||
timer.Timer = time.AfterFunc(time.Hour, func() {
|
||||
timer.runningLock.Lock()
|
||||
|
||||
timer.modifyingLock.Lock()
|
||||
@@ -42,21 +42,21 @@ func (peer *Peer) NewTimer(expirationFunction func(*Peer)) *Timer {
|
||||
expirationFunction(peer)
|
||||
timer.runningLock.Unlock()
|
||||
})
|
||||
timer.timer.Stop()
|
||||
timer.Stop()
|
||||
return timer
|
||||
}
|
||||
|
||||
func (timer *Timer) Mod(d time.Duration) {
|
||||
timer.modifyingLock.Lock()
|
||||
timer.isPending = true
|
||||
timer.timer.Reset(d)
|
||||
timer.Reset(d)
|
||||
timer.modifyingLock.Unlock()
|
||||
}
|
||||
|
||||
func (timer *Timer) Del() {
|
||||
timer.modifyingLock.Lock()
|
||||
timer.isPending = false
|
||||
timer.timer.Stop()
|
||||
timer.Stop()
|
||||
timer.modifyingLock.Unlock()
|
||||
}
|
||||
|
||||
@@ -101,11 +101,11 @@ func expiredRetransmitHandshake(peer *Peer) {
|
||||
peer.device.log.Debug.Printf("%s - Handshake did not complete after %d seconds, retrying (try %d)\n", peer, int(RekeyTimeout.Seconds()), atomic.LoadUint32(&peer.timers.handshakeAttempts)+1)
|
||||
|
||||
/* We clear the endpoint address src address, in case this is the cause of trouble. */
|
||||
peer.mutex.Lock()
|
||||
peer.Lock()
|
||||
if peer.endpoint != nil {
|
||||
peer.endpoint.ClearSrc()
|
||||
}
|
||||
peer.mutex.Unlock()
|
||||
peer.Unlock()
|
||||
|
||||
peer.SendHandshakeInitiation(true)
|
||||
}
|
||||
@@ -124,11 +124,11 @@ func expiredSendKeepalive(peer *Peer) {
|
||||
func expiredNewHandshake(peer *Peer) {
|
||||
peer.device.log.Debug.Printf("%s - Retrying handshake because we stopped hearing back after %d seconds\n", peer, int((KeepaliveTimeout + RekeyTimeout).Seconds()))
|
||||
/* We clear the endpoint address src address, in case this is the cause of trouble. */
|
||||
peer.mutex.Lock()
|
||||
peer.Lock()
|
||||
if peer.endpoint != nil {
|
||||
peer.endpoint.ClearSrc()
|
||||
}
|
||||
peer.mutex.Unlock()
|
||||
peer.Unlock()
|
||||
peer.SendHandshakeInitiation(false)
|
||||
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package device
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"golang.zx2c4.com/wireguard/ipc"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
@@ -17,23 +18,18 @@ import (
|
||||
)
|
||||
|
||||
type IPCError struct {
|
||||
Code int64
|
||||
int64
|
||||
}
|
||||
|
||||
func (s *IPCError) Error() string {
|
||||
return fmt.Sprintf("IPC error: %d", s.Code)
|
||||
func (s IPCError) Error() string {
|
||||
return fmt.Sprintf("IPC error: %d", s.int64)
|
||||
}
|
||||
|
||||
func (s *IPCError) ErrorCode() int64 {
|
||||
return s.Code
|
||||
func (s IPCError) ErrorCode() int64 {
|
||||
return s.int64
|
||||
}
|
||||
|
||||
func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
device.log.Debug.Println("UAPI: Processing get operation")
|
||||
|
||||
// create lines
|
||||
|
||||
func (device *Device) IpcGetOperation(socket *bufio.Writer) *IPCError {
|
||||
lines := make([]string, 0, 100)
|
||||
send := func(line string) {
|
||||
lines = append(lines, line)
|
||||
@@ -43,14 +39,14 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
// lock required resources
|
||||
|
||||
device.net.mutex.RLock()
|
||||
defer device.net.mutex.RUnlock()
|
||||
device.net.RLock()
|
||||
defer device.net.RUnlock()
|
||||
|
||||
device.staticIdentity.mutex.RLock()
|
||||
defer device.staticIdentity.mutex.RUnlock()
|
||||
device.staticIdentity.RLock()
|
||||
defer device.staticIdentity.RUnlock()
|
||||
|
||||
device.peers.mutex.RLock()
|
||||
defer device.peers.mutex.RUnlock()
|
||||
device.peers.RLock()
|
||||
defer device.peers.RUnlock()
|
||||
|
||||
// serialize device related values
|
||||
|
||||
@@ -69,8 +65,8 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
// serialize each peer state
|
||||
|
||||
for _, peer := range device.peers.keyMap {
|
||||
peer.mutex.RLock()
|
||||
defer peer.mutex.RUnlock()
|
||||
peer.RLock()
|
||||
defer peer.RUnlock()
|
||||
|
||||
send("public_key=" + peer.handshake.remoteStatic.ToHex())
|
||||
send("preshared_key=" + peer.handshake.presharedKey.ToHex())
|
||||
@@ -101,16 +97,14 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
for _, line := range lines {
|
||||
_, err := socket.WriteString(line + "\n")
|
||||
if err != nil {
|
||||
return &IPCError{
|
||||
Code: ipcErrorIO,
|
||||
}
|
||||
return &IPCError{ipc.IpcErrorIO}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
func (device *Device) IpcSetOperation(socket *bufio.Reader) *IPCError {
|
||||
scanner := bufio.NewScanner(socket)
|
||||
logError := device.log.Error
|
||||
logDebug := device.log.Debug
|
||||
@@ -130,7 +124,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
}
|
||||
parts := strings.Split(line, "=")
|
||||
if len(parts) != 2 {
|
||||
return &IPCError{Code: ipcErrorProtocol}
|
||||
return &IPCError{ipc.IpcErrorProtocol}
|
||||
}
|
||||
key := parts[0]
|
||||
value := parts[1]
|
||||
@@ -145,7 +139,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
err := sk.FromHex(value)
|
||||
if err != nil {
|
||||
logError.Println("Failed to set private_key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
logDebug.Println("UAPI: Updating private key")
|
||||
device.SetPrivateKey(sk)
|
||||
@@ -157,20 +151,20 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
port, err := strconv.ParseUint(value, 10, 16)
|
||||
if err != nil {
|
||||
logError.Println("Failed to parse listen_port:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
// update port and rebind
|
||||
|
||||
logDebug.Println("UAPI: Updating listen port")
|
||||
|
||||
device.net.mutex.Lock()
|
||||
device.net.Lock()
|
||||
device.net.port = uint16(port)
|
||||
device.net.mutex.Unlock()
|
||||
device.net.Unlock()
|
||||
|
||||
if err := device.BindUpdate(); err != nil {
|
||||
logError.Println("Failed to set listen_port:", err)
|
||||
return &IPCError{Code: ipcErrorPortInUse}
|
||||
return &IPCError{ipc.IpcErrorPortInUse}
|
||||
}
|
||||
|
||||
case "fwmark":
|
||||
@@ -187,14 +181,14 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
if err != nil {
|
||||
logError.Println("Invalid fwmark", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
logDebug.Println("UAPI: Updating fwmark")
|
||||
|
||||
if err := device.BindSetMark(uint32(fwmark)); err != nil {
|
||||
logError.Println("Failed to update fwmark:", err)
|
||||
return &IPCError{Code: ipcErrorPortInUse}
|
||||
return &IPCError{ipc.IpcErrorPortInUse}
|
||||
}
|
||||
|
||||
case "public_key":
|
||||
@@ -205,14 +199,14 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
case "replace_peers":
|
||||
if value != "true" {
|
||||
logError.Println("Failed to set replace_peers, invalid value:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
logDebug.Println("UAPI: Removing all peers")
|
||||
device.RemoveAllPeers()
|
||||
|
||||
default:
|
||||
logError.Println("Invalid UAPI device key:", key)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,14 +221,14 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
err := publicKey.FromHex(value)
|
||||
if err != nil {
|
||||
logError.Println("Failed to get peer by public key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
// ignore peer with public key of device
|
||||
|
||||
device.staticIdentity.mutex.RLock()
|
||||
device.staticIdentity.RLock()
|
||||
dummy = device.staticIdentity.publicKey.Equals(publicKey)
|
||||
device.staticIdentity.mutex.RUnlock()
|
||||
device.staticIdentity.RUnlock()
|
||||
|
||||
if dummy {
|
||||
peer = &Peer{}
|
||||
@@ -246,7 +240,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
peer, err = device.NewPeer(publicKey)
|
||||
if err != nil {
|
||||
logError.Println("Failed to create new peer:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
logDebug.Println(peer, "- UAPI: Created")
|
||||
}
|
||||
@@ -257,7 +251,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
if value != "true" {
|
||||
logError.Println("Failed to set remove, invalid value:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
if !dummy {
|
||||
logDebug.Println(peer, "- UAPI: Removing")
|
||||
@@ -278,7 +272,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
if err != nil {
|
||||
logError.Println("Failed to set preshared key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
case "endpoint":
|
||||
@@ -288,8 +282,8 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
logDebug.Println(peer, "- UAPI: Updating endpoint")
|
||||
|
||||
err := func() error {
|
||||
peer.mutex.Lock()
|
||||
defer peer.mutex.Unlock()
|
||||
peer.Lock()
|
||||
defer peer.Unlock()
|
||||
endpoint, err := CreateEndpoint(value)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -299,8 +293,8 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
logError.Println("Failed to set endpoint:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
logError.Println("Failed to set endpoint:", err, ":", value)
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
case "persistent_keepalive_interval":
|
||||
@@ -312,7 +306,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
secs, err := strconv.ParseUint(value, 10, 16)
|
||||
if err != nil {
|
||||
logError.Println("Failed to set persistent keepalive interval:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
old := peer.persistentKeepaliveInterval
|
||||
@@ -323,7 +317,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
if old == 0 && secs != 0 {
|
||||
if err != nil {
|
||||
logError.Println("Failed to get tun device status:", err)
|
||||
return &IPCError{Code: ipcErrorIO}
|
||||
return &IPCError{ipc.IpcErrorIO}
|
||||
}
|
||||
if device.isUp.Get() && !dummy {
|
||||
peer.SendKeepalive()
|
||||
@@ -336,7 +330,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
if value != "true" {
|
||||
logError.Println("Failed to replace allowedips, invalid value:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
if dummy {
|
||||
@@ -352,7 +346,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
_, network, err := net.ParseCIDR(value)
|
||||
if err != nil {
|
||||
logError.Println("Failed to set allowed ip:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
if dummy {
|
||||
@@ -366,12 +360,12 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
if value != "1" {
|
||||
logError.Println("Invalid protocol version:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
|
||||
default:
|
||||
logError.Println("Invalid UAPI peer key:", key)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
return &IPCError{ipc.IpcErrorInvalid}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,7 +373,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ipcHandle(device *Device, socket net.Conn) {
|
||||
func (device *Device) IpcHandle(socket net.Conn) {
|
||||
|
||||
// create buffered read/writer
|
||||
|
||||
@@ -404,12 +398,10 @@ func ipcHandle(device *Device, socket net.Conn) {
|
||||
|
||||
switch op {
|
||||
case "set=1\n":
|
||||
device.log.Debug.Println("UAPI: Set operation")
|
||||
status = ipcSetOperation(device, buffered)
|
||||
status = device.IpcSetOperation(buffered.Reader)
|
||||
|
||||
case "get=1\n":
|
||||
device.log.Debug.Println("UAPI: Get operation")
|
||||
status = ipcGetOperation(device, buffered)
|
||||
status = device.IpcGetOperation(buffered.Writer)
|
||||
|
||||
default:
|
||||
device.log.Error.Println("Invalid UAPI operation:", op)
|
||||
3
device/version.go
Normal file
3
device/version.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package device
|
||||
|
||||
const WireGuardGoVersion = "0.0.20190409"
|
||||
@@ -1,8 +1,8 @@
|
||||
// +build !android
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
9
go.mod
9
go.mod
@@ -1,7 +1,8 @@
|
||||
module git.zx2c4.com/wireguard-go
|
||||
module golang.zx2c4.com/wireguard
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9
|
||||
golang.org/x/net v0.0.0-20181207154023-610586996380
|
||||
golang.org/x/sys v0.0.0-20181210030007-2a47403f2ae5
|
||||
github.com/Microsoft/go-winio v0.4.12
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576
|
||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54
|
||||
)
|
||||
|
||||
17
go.sum
17
go.sum
@@ -1,6 +1,11 @@
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/net v0.0.0-20181207154023-610586996380 h1:zPQexyRtNYBc7bcHmehl1dH6TB3qn8zytv8cBGLDNY0=
|
||||
golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sys v0.0.0-20181210030007-2a47403f2ae5 h1:SlFRMb9PEnqzqnBRCynVOhxv4vHjB2lnIoxK6p5nzFM=
|
||||
golang.org/x/sys v0.0.0-20181210030007-2a47403f2ae5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc=
|
||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576 h1:aUX/1G2gFSs4AsJJg2cL3HuoRhCSCz733FE5GUSuaT4=
|
||||
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 h1:kcXqo9vE6fsZY5X5Rd7R1l7fTgnWaDCVmln65REefiE=
|
||||
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54 h1:xe1/2UUJRmA9iDglQSlkx8c5n3twv58+K0mPpC2zmhA=
|
||||
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// +build darwin freebsd openbsd
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package ipc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
@@ -20,10 +20,10 @@ import (
|
||||
var socketDirectory = "/var/run/wireguard"
|
||||
|
||||
const (
|
||||
ipcErrorIO = -int64(unix.EIO)
|
||||
ipcErrorProtocol = -int64(unix.EPROTO)
|
||||
ipcErrorInvalid = -int64(unix.EINVAL)
|
||||
ipcErrorPortInUse = -int64(unix.EADDRINUSE)
|
||||
IpcErrorIO = -int64(unix.EIO)
|
||||
IpcErrorProtocol = -int64(unix.EPROTO)
|
||||
IpcErrorInvalid = -int64(unix.EINVAL)
|
||||
IpcErrorPortInUse = -int64(unix.EADDRINUSE)
|
||||
socketName = "%s.sock"
|
||||
)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package ipc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/rwcancel"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
@@ -18,10 +18,10 @@ import (
|
||||
var socketDirectory = "/var/run/wireguard"
|
||||
|
||||
const (
|
||||
ipcErrorIO = -int64(unix.EIO)
|
||||
ipcErrorProtocol = -int64(unix.EPROTO)
|
||||
ipcErrorInvalid = -int64(unix.EINVAL)
|
||||
ipcErrorPortInUse = -int64(unix.EADDRINUSE)
|
||||
IpcErrorIO = -int64(unix.EIO)
|
||||
IpcErrorProtocol = -int64(unix.EPROTO)
|
||||
IpcErrorInvalid = -int64(unix.EINVAL)
|
||||
IpcErrorPortInUse = -int64(unix.EADDRINUSE)
|
||||
socketName = "%s.sock"
|
||||
)
|
||||
|
||||
87
ipc/uapi_windows.go
Normal file
87
ipc/uapi_windows.go
Normal file
@@ -0,0 +1,87 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package ipc
|
||||
|
||||
import (
|
||||
"github.com/Microsoft/go-winio"
|
||||
"net"
|
||||
)
|
||||
|
||||
//TODO: replace these with actual standard windows error numbers from the win package
|
||||
const (
|
||||
IpcErrorIO = -int64(5)
|
||||
IpcErrorProtocol = -int64(71)
|
||||
IpcErrorInvalid = -int64(22)
|
||||
IpcErrorPortInUse = -int64(98)
|
||||
)
|
||||
|
||||
type UAPIListener struct {
|
||||
listener net.Listener // unix socket listener
|
||||
connNew chan net.Conn
|
||||
connErr chan error
|
||||
kqueueFd int
|
||||
keventFd int
|
||||
}
|
||||
|
||||
func (l *UAPIListener) Accept() (net.Conn, error) {
|
||||
for {
|
||||
select {
|
||||
case conn := <-l.connNew:
|
||||
return conn, nil
|
||||
|
||||
case err := <-l.connErr:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (l *UAPIListener) Close() error {
|
||||
return l.listener.Close()
|
||||
}
|
||||
|
||||
func (l *UAPIListener) Addr() net.Addr {
|
||||
return l.listener.Addr()
|
||||
}
|
||||
|
||||
func GetSystemSecurityDescriptor() string {
|
||||
//
|
||||
// SDDL encoded.
|
||||
//
|
||||
// (system = SECURITY_NT_AUTHORITY | SECURITY_LOCAL_SYSTEM_RID)
|
||||
// owner: system
|
||||
// grant: GENERIC_ALL to system
|
||||
//
|
||||
return "O:SYD:(A;;GA;;;SY)"
|
||||
}
|
||||
|
||||
func UAPIListen(name string) (net.Listener, error) {
|
||||
config := winio.PipeConfig{
|
||||
SecurityDescriptor: GetSystemSecurityDescriptor(),
|
||||
}
|
||||
listener, err := winio.ListenPipe("\\\\.\\pipe\\WireGuard\\"+name, &config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uapi := &UAPIListener{
|
||||
listener: listener,
|
||||
connNew: make(chan net.Conn, 1),
|
||||
connErr: make(chan error, 1),
|
||||
}
|
||||
|
||||
go func(l *UAPIListener) {
|
||||
for {
|
||||
conn, err := l.listener.Accept()
|
||||
if err != nil {
|
||||
l.connErr <- err
|
||||
break
|
||||
}
|
||||
l.connNew <- conn
|
||||
}
|
||||
}(uapi)
|
||||
|
||||
return uapi, nil
|
||||
}
|
||||
45
main.go
45
main.go
@@ -1,13 +1,17 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
// +build !windows
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/ipc"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
@@ -74,7 +78,7 @@ func warning() {
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 2 && os.Args[1] == "--version" {
|
||||
fmt.Printf("wireguard-go v%s\n\nUserspace WireGuard daemon for %s-%s.\nInformation available at https://www.wireguard.com.\nCopyright (C) Jason A. Donenfeld <Jason@zx2c4.com>.\n", WireGuardGoVersion, runtime.GOOS, runtime.GOARCH)
|
||||
fmt.Printf("wireguard-go v%s\n\nUserspace WireGuard daemon for %s-%s.\nInformation available at https://www.wireguard.com.\nCopyright (C) Jason A. Donenfeld <Jason@zx2c4.com>.\n", device.WireGuardGoVersion, runtime.GOOS, runtime.GOARCH)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -117,15 +121,15 @@ func main() {
|
||||
logLevel := func() int {
|
||||
switch os.Getenv("LOG_LEVEL") {
|
||||
case "debug":
|
||||
return LogLevelDebug
|
||||
return device.LogLevelDebug
|
||||
case "info":
|
||||
return LogLevelInfo
|
||||
return device.LogLevelInfo
|
||||
case "error":
|
||||
return LogLevelError
|
||||
return device.LogLevelError
|
||||
case "silent":
|
||||
return LogLevelSilent
|
||||
return device.LogLevelSilent
|
||||
}
|
||||
return LogLevelInfo
|
||||
return device.LogLevelInfo
|
||||
}()
|
||||
|
||||
// open TUN device (or use supplied fd)
|
||||
@@ -133,7 +137,7 @@ func main() {
|
||||
tun, err := func() (tun.TUNDevice, error) {
|
||||
tunFdStr := os.Getenv(ENV_WG_TUN_FD)
|
||||
if tunFdStr == "" {
|
||||
return tun.CreateTUN(interfaceName, DefaultMTU)
|
||||
return tun.CreateTUN(interfaceName, device.DefaultMTU)
|
||||
}
|
||||
|
||||
// construct tun device from supplied fd
|
||||
@@ -143,8 +147,13 @@ func main() {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = syscall.SetNonblock(int(fd), true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file := os.NewFile(uintptr(fd), "")
|
||||
return tun.CreateTUNFromFile(file, DefaultMTU)
|
||||
return tun.CreateTUNFromFile(file, device.DefaultMTU)
|
||||
}()
|
||||
|
||||
if err == nil {
|
||||
@@ -154,12 +163,12 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
logger := NewLogger(
|
||||
logger := device.NewLogger(
|
||||
logLevel,
|
||||
fmt.Sprintf("(%s) ", interfaceName),
|
||||
)
|
||||
|
||||
logger.Info.Println("Starting wireguard-go version", WireGuardGoVersion)
|
||||
logger.Info.Println("Starting wireguard-go version", device.WireGuardGoVersion)
|
||||
|
||||
logger.Debug.Println("Debug log enabled")
|
||||
|
||||
@@ -173,7 +182,7 @@ func main() {
|
||||
fileUAPI, err := func() (*os.File, error) {
|
||||
uapiFdStr := os.Getenv(ENV_WG_UAPI_FD)
|
||||
if uapiFdStr == "" {
|
||||
return UAPIOpen(interfaceName)
|
||||
return ipc.UAPIOpen(interfaceName)
|
||||
}
|
||||
|
||||
// use supplied fd
|
||||
@@ -199,7 +208,7 @@ func main() {
|
||||
env = append(env, fmt.Sprintf("%s=4", ENV_WG_UAPI_FD))
|
||||
env = append(env, fmt.Sprintf("%s=1", ENV_WG_PROCESS_FOREGROUND))
|
||||
files := [3]*os.File{}
|
||||
if os.Getenv("LOG_LEVEL") != "" && logLevel != LogLevelSilent {
|
||||
if os.Getenv("LOG_LEVEL") != "" && logLevel != device.LogLevelSilent {
|
||||
files[0], _ = os.Open(os.DevNull)
|
||||
files[1] = os.Stdout
|
||||
files[2] = os.Stderr
|
||||
@@ -239,14 +248,14 @@ func main() {
|
||||
return
|
||||
}
|
||||
|
||||
device := NewDevice(tun, logger)
|
||||
device := device.NewDevice(tun, logger)
|
||||
|
||||
logger.Info.Println("Device started")
|
||||
|
||||
errs := make(chan error)
|
||||
term := make(chan os.Signal, 1)
|
||||
|
||||
uapi, err := UAPIListen(interfaceName, fileUAPI)
|
||||
uapi, err := ipc.UAPIListen(interfaceName, fileUAPI)
|
||||
if err != nil {
|
||||
logger.Error.Println("Failed to listen on uapi socket:", err)
|
||||
os.Exit(ExitSetupFailed)
|
||||
@@ -259,7 +268,7 @@ func main() {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
go ipcHandle(device, conn)
|
||||
go device.IpcHandle(conn)
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
91
main_windows.go
Normal file
91
main_windows.go
Normal file
@@ -0,0 +1,91 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"golang.zx2c4.com/wireguard/device"
|
||||
"golang.zx2c4.com/wireguard/ipc"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
)
|
||||
|
||||
const (
|
||||
ExitSetupSuccess = 0
|
||||
ExitSetupFailed = 1
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
os.Exit(ExitSetupFailed)
|
||||
}
|
||||
interfaceName := os.Args[1]
|
||||
|
||||
logger := device.NewLogger(
|
||||
device.LogLevelDebug,
|
||||
fmt.Sprintf("(%s) ", interfaceName),
|
||||
)
|
||||
logger.Info.Println("Starting wireguard-go version", WireGuardGoVersion)
|
||||
logger.Debug.Println("Debug log enabled")
|
||||
|
||||
tun, err := tun.CreateTUN(interfaceName)
|
||||
if err == nil {
|
||||
realInterfaceName, err2 := tun.Name()
|
||||
if err2 == nil {
|
||||
interfaceName = realInterfaceName
|
||||
}
|
||||
} else {
|
||||
logger.Error.Println("Failed to create TUN device:", err)
|
||||
os.Exit(ExitSetupFailed)
|
||||
}
|
||||
|
||||
device := device.NewDevice(tun, logger)
|
||||
device.Up()
|
||||
logger.Info.Println("Device started")
|
||||
|
||||
uapi, err := ipc.UAPIListen(interfaceName)
|
||||
if err != nil {
|
||||
logger.Error.Println("Failed to listen on uapi socket:", err)
|
||||
os.Exit(ExitSetupFailed)
|
||||
}
|
||||
|
||||
errs := make(chan error)
|
||||
term := make(chan os.Signal, 1)
|
||||
|
||||
go func() {
|
||||
for {
|
||||
conn, err := uapi.Accept()
|
||||
if err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
go device.IpcHandle(conn)
|
||||
}
|
||||
}()
|
||||
logger.Info.Println("UAPI listener started")
|
||||
|
||||
// wait for program to terminate
|
||||
|
||||
signal.Notify(term, os.Interrupt)
|
||||
signal.Notify(term, os.Kill)
|
||||
signal.Notify(term, syscall.SIGTERM)
|
||||
|
||||
select {
|
||||
case <-term:
|
||||
case <-errs:
|
||||
case <-device.Wait():
|
||||
}
|
||||
|
||||
// clean up
|
||||
|
||||
uapi.Close()
|
||||
device.Close()
|
||||
|
||||
logger.Info.Println("Shutting down")
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
// +build !linux,!openbsd,!freebsd
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
func (bind *NativeBind) SetMark(mark uint32) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package ratelimiter
|
||||
@@ -20,21 +20,21 @@ const (
|
||||
)
|
||||
|
||||
type RatelimiterEntry struct {
|
||||
mutex sync.Mutex
|
||||
sync.Mutex
|
||||
lastTime time.Time
|
||||
tokens int64
|
||||
}
|
||||
|
||||
type Ratelimiter struct {
|
||||
mutex sync.RWMutex
|
||||
sync.RWMutex
|
||||
stopReset chan struct{}
|
||||
tableIPv4 map[[net.IPv4len]byte]*RatelimiterEntry
|
||||
tableIPv6 map[[net.IPv6len]byte]*RatelimiterEntry
|
||||
}
|
||||
|
||||
func (rate *Ratelimiter) Close() {
|
||||
rate.mutex.Lock()
|
||||
defer rate.mutex.Unlock()
|
||||
rate.Lock()
|
||||
defer rate.Unlock()
|
||||
|
||||
if rate.stopReset != nil {
|
||||
close(rate.stopReset)
|
||||
@@ -42,8 +42,8 @@ func (rate *Ratelimiter) Close() {
|
||||
}
|
||||
|
||||
func (rate *Ratelimiter) Init() {
|
||||
rate.mutex.Lock()
|
||||
defer rate.mutex.Unlock()
|
||||
rate.Lock()
|
||||
defer rate.Unlock()
|
||||
|
||||
// stop any ongoing garbage collection routine
|
||||
|
||||
@@ -71,23 +71,23 @@ func (rate *Ratelimiter) Init() {
|
||||
}
|
||||
case <-ticker.C:
|
||||
func() {
|
||||
rate.mutex.Lock()
|
||||
defer rate.mutex.Unlock()
|
||||
rate.Lock()
|
||||
defer rate.Unlock()
|
||||
|
||||
for key, entry := range rate.tableIPv4 {
|
||||
entry.mutex.Lock()
|
||||
entry.Lock()
|
||||
if time.Now().Sub(entry.lastTime) > garbageCollectTime {
|
||||
delete(rate.tableIPv4, key)
|
||||
}
|
||||
entry.mutex.Unlock()
|
||||
entry.Unlock()
|
||||
}
|
||||
|
||||
for key, entry := range rate.tableIPv6 {
|
||||
entry.mutex.Lock()
|
||||
entry.Lock()
|
||||
if time.Now().Sub(entry.lastTime) > garbageCollectTime {
|
||||
delete(rate.tableIPv6, key)
|
||||
}
|
||||
entry.mutex.Unlock()
|
||||
entry.Unlock()
|
||||
}
|
||||
|
||||
if len(rate.tableIPv4) == 0 && len(rate.tableIPv6) == 0 {
|
||||
@@ -109,7 +109,7 @@ func (rate *Ratelimiter) Allow(ip net.IP) bool {
|
||||
IPv4 := ip.To4()
|
||||
IPv6 := ip.To16()
|
||||
|
||||
rate.mutex.RLock()
|
||||
rate.RLock()
|
||||
|
||||
if IPv4 != nil {
|
||||
copy(keyIPv4[:], IPv4)
|
||||
@@ -119,7 +119,7 @@ func (rate *Ratelimiter) Allow(ip net.IP) bool {
|
||||
entry = rate.tableIPv6[keyIPv6]
|
||||
}
|
||||
|
||||
rate.mutex.RUnlock()
|
||||
rate.RUnlock()
|
||||
|
||||
// make new entry if not found
|
||||
|
||||
@@ -127,7 +127,7 @@ func (rate *Ratelimiter) Allow(ip net.IP) bool {
|
||||
entry = new(RatelimiterEntry)
|
||||
entry.tokens = maxTokens - packetCost
|
||||
entry.lastTime = time.Now()
|
||||
rate.mutex.Lock()
|
||||
rate.Lock()
|
||||
if IPv4 != nil {
|
||||
rate.tableIPv4[keyIPv4] = entry
|
||||
if len(rate.tableIPv4) == 1 && len(rate.tableIPv6) == 0 {
|
||||
@@ -139,13 +139,13 @@ func (rate *Ratelimiter) Allow(ip net.IP) bool {
|
||||
rate.stopReset <- struct{}{}
|
||||
}
|
||||
}
|
||||
rate.mutex.Unlock()
|
||||
rate.Unlock()
|
||||
return true
|
||||
}
|
||||
|
||||
// add tokens to entry
|
||||
|
||||
entry.mutex.Lock()
|
||||
entry.Lock()
|
||||
now := time.Now()
|
||||
entry.tokens += now.Sub(entry.lastTime).Nanoseconds()
|
||||
entry.lastTime = now
|
||||
@@ -157,9 +157,9 @@ func (rate *Ratelimiter) Allow(ip net.IP) bool {
|
||||
|
||||
if entry.tokens > packetCost {
|
||||
entry.tokens -= packetCost
|
||||
entry.mutex.Unlock()
|
||||
entry.Unlock()
|
||||
return true
|
||||
}
|
||||
entry.mutex.Unlock()
|
||||
entry.Unlock()
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package ratelimiter
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package replay
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package replay
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
@@ -8,15 +8,15 @@ package rwcancel
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
type fdSet struct {
|
||||
fdset unix.FdSet
|
||||
unix.FdSet
|
||||
}
|
||||
|
||||
func (fdset *fdSet) set(i int) {
|
||||
bits := 32 << (^uint(0) >> 63)
|
||||
fdset.fdset.Bits[i/bits] |= 1 << uint(i%bits)
|
||||
fdset.Bits[i/bits] |= 1 << uint(i%bits)
|
||||
}
|
||||
|
||||
func (fdset *fdSet) check(i int) bool {
|
||||
bits := 32 << (^uint(0) >> 63)
|
||||
return (fdset.fdset.Bits[i/bits] & (1 << uint(i%bits))) != 0
|
||||
return (fdset.Bits[i/bits] & (1 << uint(i%bits))) != 0
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
@@ -59,7 +59,7 @@ func (rw *RWCancel) ReadyRead() bool {
|
||||
fdset := fdSet{}
|
||||
fdset.set(rw.fd)
|
||||
fdset.set(closeFd)
|
||||
err := unixSelect(max(rw.fd, closeFd)+1, &fdset.fdset, nil, nil, nil)
|
||||
err := unixSelect(max(rw.fd, closeFd)+1, &fdset.FdSet, nil, nil, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func (rw *RWCancel) ReadyWrite() bool {
|
||||
fdset := fdSet{}
|
||||
fdset.set(rw.fd)
|
||||
fdset.set(closeFd)
|
||||
err := unixSelect(max(rw.fd, closeFd)+1, nil, &fdset.fdset, nil, nil)
|
||||
err := unixSelect(max(rw.fd, closeFd)+1, nil, &fdset.FdSet, nil, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// +build !linux
|
||||
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package rwcancel
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tai64n
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
)
|
||||
|
||||
const TimestampSize = 12
|
||||
const base = uint64(4611686018427387914)
|
||||
const base = uint64(0x400000000000000a)
|
||||
const whitenerMask = uint32(0x1000000 - 1)
|
||||
|
||||
type Timestamp [TimestampSize]byte
|
||||
|
||||
@@ -20,7 +21,7 @@ func Now() Timestamp {
|
||||
var tai64n Timestamp
|
||||
now := time.Now()
|
||||
secs := base + uint64(now.Unix())
|
||||
nano := uint32(now.Nanosecond())
|
||||
nano := uint32(now.Nanosecond()) &^ whitenerMask
|
||||
binary.BigEndian.PutUint64(tai64n[:], secs)
|
||||
binary.BigEndian.PutUint32(tai64n[8:], nano)
|
||||
return tai64n
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tai64n
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
package tun
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"git.zx2c4.com/wireguard-go/tun"
|
||||
"golang.zx2c4.com/wireguard/tun"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
24
tun/operateonfd.go
Normal file
24
tun/operateonfd.go
Normal file
@@ -0,0 +1,24 @@
|
||||
// +build !windows
|
||||
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (tun *NativeTun) operateOnFd(fn func(fd uintptr)) {
|
||||
sysconn, err := tun.tunFile.SyscallConn()
|
||||
if err != nil {
|
||||
tun.errors <- fmt.Errorf("unable to find sysconn for tunfile: %s", err.Error())
|
||||
return
|
||||
}
|
||||
err = sysconn.Control(fn)
|
||||
if err != nil {
|
||||
tun.errors <- fmt.Errorf("unable to control sysconn for tunfile: %s", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
type TUNEvent int
|
||||
|
||||
@@ -19,6 +21,7 @@ type TUNDevice interface {
|
||||
File() *os.File // returns the file descriptor of the device
|
||||
Read([]byte, int) (int, error) // read a packet from the device (without any additional headers)
|
||||
Write([]byte, int) (int, error) // writes a packet to the device (without any additional headers)
|
||||
Flush() error // flush all previous writes to the device
|
||||
MTU() (int, error) // returns the MTU of the device
|
||||
Name() (string, error) // fetches and returns the current name
|
||||
Events() chan TUNEvent // returns a constant channel of events related to the device
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/net/ipv6"
|
||||
"golang.org/x/sys/unix"
|
||||
"io/ioutil"
|
||||
@@ -33,11 +31,9 @@ type sockaddrCtl struct {
|
||||
scReserved [5]uint32
|
||||
}
|
||||
|
||||
type nativeTun struct {
|
||||
type NativeTun struct {
|
||||
name string
|
||||
tunFile *os.File
|
||||
fd uintptr
|
||||
rwcancel *rwcancel.RWCancel
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
routeSocket int
|
||||
@@ -45,7 +41,7 @@ type nativeTun struct {
|
||||
|
||||
var sockaddrCtlSize uintptr = 32
|
||||
|
||||
func (tun *nativeTun) routineRouteListener(tunIfindex int) {
|
||||
func (tun *NativeTun) routineRouteListener(tunIfindex int) {
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
@@ -155,12 +151,16 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
return nil, fmt.Errorf("SYS_CONNECT: %v", errno)
|
||||
}
|
||||
|
||||
err = syscall.SetNonblock(fd, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tun, err := CreateTUNFromFile(os.NewFile(uintptr(fd), ""), mtu)
|
||||
|
||||
if err == nil && name == "utun" {
|
||||
fname := os.Getenv("WG_TUN_NAME_FILE")
|
||||
if fname != "" {
|
||||
ioutil.WriteFile(fname, []byte(tun.(*nativeTun).name+"\n"), 0400)
|
||||
ioutil.WriteFile(fname, []byte(tun.(*NativeTun).name+"\n"), 0400)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,12 +168,10 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
}
|
||||
|
||||
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
tun := &nativeTun{
|
||||
tun := &NativeTun{
|
||||
tunFile: file,
|
||||
fd: file.Fd(),
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
errors: make(chan error, 5),
|
||||
}
|
||||
|
||||
name, err := tun.Name()
|
||||
@@ -194,12 +192,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(tun.fd))
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
@@ -208,29 +200,33 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
go tun.routineRouteListener(tunIfindex)
|
||||
|
||||
if mtu > 0 {
|
||||
err = tun.setMTU(mtu)
|
||||
if err != nil {
|
||||
tun.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return tun, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Name() (string, error) {
|
||||
|
||||
func (tun *NativeTun) Name() (string, error) {
|
||||
var ifName struct {
|
||||
name [16]byte
|
||||
}
|
||||
ifNameSize := uintptr(16)
|
||||
|
||||
_, _, errno := unix.Syscall6(
|
||||
var errno syscall.Errno
|
||||
tun.operateOnFd(func(fd uintptr) {
|
||||
_, _, errno = unix.Syscall6(
|
||||
unix.SYS_GETSOCKOPT,
|
||||
uintptr(tun.fd),
|
||||
fd,
|
||||
2, /* #define SYSPROTO_CONTROL 2 */
|
||||
2, /* #define UTUN_OPT_IFNAME 2 */
|
||||
uintptr(unsafe.Pointer(&ifName)),
|
||||
uintptr(unsafe.Pointer(&ifNameSize)), 0)
|
||||
})
|
||||
|
||||
if errno != 0 {
|
||||
return "", fmt.Errorf("SYS_GETSOCKOPT: %v", errno)
|
||||
@@ -240,15 +236,15 @@ func (tun *nativeTun) Name() (string, error) {
|
||||
return tun.name, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
return tun.tunFile
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Events() chan TUNEvent {
|
||||
func (tun *NativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
@@ -262,19 +258,7 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
for {
|
||||
n, err := tun.doRead(buff, offset)
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !tun.rwcancel.ReadyRead() {
|
||||
return 0, errors.New("tun device closed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
// reserve space for header
|
||||
|
||||
@@ -297,13 +281,17 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
return tun.tunFile.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err3 error
|
||||
err1 := tun.rwcancel.Cancel()
|
||||
err2 := tun.tunFile.Close()
|
||||
func (tun *NativeTun) Flush() error {
|
||||
//TODO: can flushing be implemented by buffering and using sendmmsg?
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Close() error {
|
||||
var err2 error
|
||||
err1 := tun.tunFile.Close()
|
||||
if tun.routeSocket != -1 {
|
||||
unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
|
||||
err3 = unix.Close(tun.routeSocket)
|
||||
err2 = unix.Close(tun.routeSocket)
|
||||
tun.routeSocket = -1
|
||||
} else if tun.events != nil {
|
||||
close(tun.events)
|
||||
@@ -311,13 +299,10 @@ func (tun *nativeTun) Close() error {
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return err3
|
||||
}
|
||||
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
func (tun *NativeTun) setMTU(n int) error {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
@@ -354,7 +339,7 @@ func (tun *nativeTun) setMTU(n int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) MTU() (int, error) {
|
||||
func (tun *NativeTun) MTU() (int, error) {
|
||||
|
||||
// open datagram socket
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/net/ipv6"
|
||||
"golang.org/x/sys/unix"
|
||||
"net"
|
||||
@@ -49,17 +48,15 @@ type ifstat struct {
|
||||
Ascii [_IFSTATMAX]byte
|
||||
}
|
||||
|
||||
type nativeTun struct {
|
||||
type NativeTun struct {
|
||||
name string
|
||||
tunFile *os.File
|
||||
fd uintptr
|
||||
rwcancel *rwcancel.RWCancel
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
routeSocket int
|
||||
}
|
||||
|
||||
func (tun *nativeTun) routineRouteListener(tunIfindex int) {
|
||||
func (tun *NativeTun) routineRouteListener(tunIfindex int) {
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
@@ -239,12 +236,15 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
}
|
||||
|
||||
tunFile, err := os.OpenFile("/dev/tun", unix.O_RDWR, 0)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tunfd := tunFile.Fd()
|
||||
assignedName, err := tunName(tunfd)
|
||||
|
||||
tun := NativeTun{tunFile: tunFile}
|
||||
var assignedName string
|
||||
tun.operateOnFd(func(fd uintptr) {
|
||||
assignedName, err = tunName(fd)
|
||||
})
|
||||
if err != nil {
|
||||
tunFile.Close()
|
||||
return nil, err
|
||||
@@ -252,12 +252,15 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
|
||||
// Enable ifhead mode, otherwise tun will complain if it gets a non-AF_INET packet
|
||||
ifheadmode := 1
|
||||
_, _, errno := unix.Syscall(
|
||||
var errno syscall.Errno
|
||||
tun.operateOnFd(func(fd uintptr) {
|
||||
_, _, errno = unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
uintptr(tunfd),
|
||||
fd,
|
||||
uintptr(_TUNSIFHEAD),
|
||||
uintptr(unsafe.Pointer(&ifheadmode)),
|
||||
)
|
||||
})
|
||||
|
||||
if errno != 0 {
|
||||
return nil, fmt.Errorf("error %s", errno.Error())
|
||||
@@ -304,9 +307,8 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
|
||||
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
tun := &nativeTun{
|
||||
tun := &NativeTun{
|
||||
tunFile: file,
|
||||
fd: file.Fd(),
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
}
|
||||
@@ -329,12 +331,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(tun.fd))
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
@@ -352,8 +348,12 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
return tun, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Name() (string, error) {
|
||||
name, err := tunName(tun.fd)
|
||||
func (tun *NativeTun) Name() (string, error) {
|
||||
var name string
|
||||
var err error
|
||||
tun.operateOnFd(func(fd uintptr) {
|
||||
name, err = tunName(fd)
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -361,15 +361,15 @@ func (tun *nativeTun) Name() (string, error) {
|
||||
return name, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
return tun.tunFile
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Events() chan TUNEvent {
|
||||
func (tun *NativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
@@ -383,19 +383,7 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
for {
|
||||
n, err := tun.doRead(buff, offset)
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !tun.rwcancel.ReadyRead() {
|
||||
return 0, errors.New("tun device closed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
// reserve space for header
|
||||
|
||||
@@ -418,14 +406,18 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
return tun.tunFile.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err4 error
|
||||
err1 := tun.rwcancel.Cancel()
|
||||
err2 := tun.tunFile.Close()
|
||||
err3 := tunDestroy(tun.name)
|
||||
func (tun *NativeTun) Flush() error {
|
||||
//TODO: can flushing be implemented by buffering and using sendmmsg?
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Close() error {
|
||||
var err3 error
|
||||
err1 := tun.tunFile.Close()
|
||||
err2 := tunDestroy(tun.name)
|
||||
if tun.routeSocket != -1 {
|
||||
unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
|
||||
err4 = unix.Close(tun.routeSocket)
|
||||
err3 = unix.Close(tun.routeSocket)
|
||||
tun.routeSocket = -1
|
||||
} else if tun.events != nil {
|
||||
close(tun.events)
|
||||
@@ -436,13 +428,10 @@ func (tun *nativeTun) Close() error {
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
if err3 != nil {
|
||||
return err3
|
||||
}
|
||||
return err4
|
||||
}
|
||||
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
func (tun *NativeTun) setMTU(n int) error {
|
||||
// open datagram socket
|
||||
|
||||
var fd int
|
||||
@@ -479,7 +468,7 @@ func (tun *nativeTun) setMTU(n int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) MTU() (int, error) {
|
||||
func (tun *NativeTun) MTU() (int, error) {
|
||||
// open datagram socket
|
||||
|
||||
fd, err := unix.Socket(
|
||||
|
||||
149
tun/tun_linux.go
149
tun/tun_linux.go
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
@@ -12,13 +12,13 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/net/ipv6"
|
||||
"golang.org/x/sys/unix"
|
||||
"golang.zx2c4.com/wireguard/rwcancel"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -28,10 +28,8 @@ const (
|
||||
ifReqSize = unix.IFNAMSIZ + 64
|
||||
)
|
||||
|
||||
type nativeTun struct {
|
||||
type NativeTun struct {
|
||||
tunFile *os.File
|
||||
fd uintptr
|
||||
fdCancel *rwcancel.RWCancel
|
||||
index int32 // if index
|
||||
name string // name of interface
|
||||
errors chan error // async error handling
|
||||
@@ -43,18 +41,26 @@ type nativeTun struct {
|
||||
statusListenersShutdown chan struct{}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
return tun.tunFile
|
||||
}
|
||||
|
||||
func (tun *nativeTun) routineHackListener() {
|
||||
func (tun *NativeTun) routineHackListener() {
|
||||
defer tun.hackListenerClosed.Unlock()
|
||||
/* This is needed for the detection to work across network namespaces
|
||||
* If you are reading this and know a better method, please get in touch.
|
||||
*/
|
||||
fd := int(tun.fd)
|
||||
for {
|
||||
_, err := unix.Write(fd, nil)
|
||||
sysconn, err := tun.tunFile.SyscallConn()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err2 := sysconn.Control(func(fd uintptr) {
|
||||
_, err = unix.Write(int(fd), nil)
|
||||
})
|
||||
if err2 != nil {
|
||||
return
|
||||
}
|
||||
switch err {
|
||||
case unix.EINVAL:
|
||||
tun.events <- TUNEventUp
|
||||
@@ -87,7 +93,7 @@ func createNetlinkSocket() (int, error) {
|
||||
return sock, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) routineNetlinkListener() {
|
||||
func (tun *NativeTun) routineNetlinkListener() {
|
||||
defer func() {
|
||||
unix.Close(tun.netlinkSock)
|
||||
tun.hackListenerClosed.Lock()
|
||||
@@ -157,21 +163,17 @@ func (tun *nativeTun) routineNetlinkListener() {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) isUp() (bool, error) {
|
||||
func (tun *NativeTun) isUp() (bool, error) {
|
||||
inter, err := net.InterfaceByName(tun.name)
|
||||
return inter.Flags&net.FlagUp != 0, err
|
||||
}
|
||||
|
||||
func getDummySock() (int, error) {
|
||||
return unix.Socket(
|
||||
func getIFIndex(name string) (int32, error) {
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
func getIFIndex(name string) (int32, error) {
|
||||
fd, err := getDummySock()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -194,10 +196,8 @@ func getIFIndex(name string) (int32, error) {
|
||||
return *(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ])), nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
|
||||
func (tun *NativeTun) setMTU(n int) error {
|
||||
// open datagram socket
|
||||
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
@@ -229,10 +229,8 @@ func (tun *nativeTun) setMTU(n int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) MTU() (int, error) {
|
||||
|
||||
func (tun *NativeTun) MTU() (int, error) {
|
||||
// open datagram socket
|
||||
|
||||
fd, err := unix.Socket(
|
||||
unix.AF_INET,
|
||||
unix.SOCK_DGRAM,
|
||||
@@ -256,23 +254,32 @@ func (tun *nativeTun) MTU() (int, error) {
|
||||
uintptr(unsafe.Pointer(&ifr[0])),
|
||||
)
|
||||
if errno != 0 {
|
||||
return 0, errors.New("failed to get MTU of TUN device: " + strconv.FormatInt(int64(errno), 10))
|
||||
return 0, errors.New("failed to get MTU of TUN device: " + errno.Error())
|
||||
}
|
||||
|
||||
return int(*(*int32)(unsafe.Pointer(&ifr[unix.IFNAMSIZ]))), nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Name() (string, error) {
|
||||
|
||||
func (tun *NativeTun) Name() (string, error) {
|
||||
sysconn, err := tun.tunFile.SyscallConn()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var ifr [ifReqSize]byte
|
||||
_, _, errno := unix.Syscall(
|
||||
var errno syscall.Errno
|
||||
err = sysconn.Control(func(fd uintptr) {
|
||||
_, _, errno = unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
tun.fd,
|
||||
fd,
|
||||
uintptr(unix.TUNGETIFF),
|
||||
uintptr(unsafe.Pointer(&ifr[0])),
|
||||
)
|
||||
})
|
||||
if err != nil {
|
||||
return "", errors.New("failed to get name of TUN device: " + err.Error())
|
||||
}
|
||||
if errno != 0 {
|
||||
return "", errors.New("failed to get name of TUN device: " + strconv.FormatInt(int64(errno), 10))
|
||||
return "", errors.New("failed to get name of TUN device: " + errno.Error())
|
||||
}
|
||||
nullStr := ifr[:]
|
||||
i := bytes.IndexByte(nullStr, 0)
|
||||
@@ -283,7 +290,7 @@ func (tun *nativeTun) Name() (string, error) {
|
||||
return tun.name, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
if tun.nopi {
|
||||
buff = buff[offset:]
|
||||
@@ -311,7 +318,12 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
return tun.tunFile.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
func (tun *NativeTun) Flush() error {
|
||||
//TODO: can flushing be implemented by buffering and using sendmmsg?
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
@@ -329,23 +341,11 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
for {
|
||||
n, err := tun.doRead(buff, offset)
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !tun.fdCancel.ReadyRead() {
|
||||
return 0, errors.New("tun device closed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Events() chan TUNEvent {
|
||||
func (tun *NativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Close() error {
|
||||
func (tun *NativeTun) Close() error {
|
||||
var err1 error
|
||||
if tun.statusListenersShutdown != nil {
|
||||
close(tun.statusListenersShutdown)
|
||||
@@ -356,16 +356,12 @@ func (tun *nativeTun) Close() error {
|
||||
close(tun.events)
|
||||
}
|
||||
err2 := tun.tunFile.Close()
|
||||
err3 := tun.fdCancel.Cancel()
|
||||
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return err3
|
||||
}
|
||||
|
||||
func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
nfd, err := unix.Open(cloneDevicePath, os.O_RDWR, 0)
|
||||
@@ -373,13 +369,6 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fd := os.NewFile(uintptr(nfd), cloneDevicePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create new device
|
||||
|
||||
var ifr [ifReqSize]byte
|
||||
var flags uint16 = unix.IFF_TUN // | unix.IFF_NO_PI (disabled for TUN status hack)
|
||||
nameBytes := []byte(name)
|
||||
@@ -391,21 +380,28 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
|
||||
_, _, errno := unix.Syscall(
|
||||
unix.SYS_IOCTL,
|
||||
fd.Fd(),
|
||||
uintptr(nfd),
|
||||
uintptr(unix.TUNSETIFF),
|
||||
uintptr(unsafe.Pointer(&ifr[0])),
|
||||
)
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
err = unix.SetNonblock(nfd, true)
|
||||
|
||||
// Note that the above -- open,ioctl,nonblock -- must happen prior to handing it to netpoll as below this line.
|
||||
|
||||
fd := os.NewFile(uintptr(nfd), cloneDevicePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return CreateTUNFromFile(fd, mtu)
|
||||
}
|
||||
|
||||
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
tun := &nativeTun{
|
||||
tun := &NativeTun{
|
||||
tunFile: file,
|
||||
fd: file.Fd(),
|
||||
events: make(chan TUNEvent, 5),
|
||||
errors: make(chan error, 5),
|
||||
statusListenersShutdown: make(chan struct{}),
|
||||
@@ -413,15 +409,8 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
}
|
||||
var err error
|
||||
|
||||
tun.fdCancel, err = rwcancel.NewRWCancel(int(tun.fd))
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = tun.Name()
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -434,12 +423,11 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
tun.netlinkSock, err = createNetlinkSocket()
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
tun.netlinkCancel, err = rwcancel.NewRWCancel(tun.netlinkSock)
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
unix.Close(tun.netlinkSock)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -449,9 +437,28 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
err = tun.setMTU(mtu)
|
||||
if err != nil {
|
||||
tun.Close()
|
||||
unix.Close(tun.netlinkSock)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tun, nil
|
||||
}
|
||||
|
||||
func CreateUnmonitoredTUNFromFD(fd int) (TUNDevice, string, error) {
|
||||
err := unix.SetNonblock(fd, true)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
file := os.NewFile(uintptr(fd), "/dev/tun")
|
||||
tun := &NativeTun{
|
||||
tunFile: file,
|
||||
events: make(chan TUNEvent, 5),
|
||||
errors: make(chan error, 5),
|
||||
nopi: true,
|
||||
}
|
||||
name, err := tun.Name()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return tun, name, nil
|
||||
}
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2017-2018 WireGuard LLC. All Rights Reserved.
|
||||
* Copyright (C) 2017-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.zx2c4.com/wireguard-go/rwcancel"
|
||||
"golang.org/x/net/ipv6"
|
||||
"golang.org/x/sys/unix"
|
||||
"io/ioutil"
|
||||
@@ -27,16 +25,15 @@ type ifreq_mtu struct {
|
||||
|
||||
const _TUNSIFMODE = 0x8004745d
|
||||
|
||||
type nativeTun struct {
|
||||
type NativeTun struct {
|
||||
name string
|
||||
tunFile *os.File
|
||||
rwcancel *rwcancel.RWCancel
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
routeSocket int
|
||||
}
|
||||
|
||||
func (tun *nativeTun) routineRouteListener(tunIfindex int) {
|
||||
func (tun *NativeTun) routineRouteListener(tunIfindex int) {
|
||||
var (
|
||||
statusUp bool
|
||||
statusMTU int
|
||||
@@ -134,7 +131,7 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
if err == nil && name == "tun" {
|
||||
fname := os.Getenv("WG_TUN_NAME_FILE")
|
||||
if fname != "" {
|
||||
ioutil.WriteFile(fname, []byte(tun.(*nativeTun).name+"\n"), 0400)
|
||||
ioutil.WriteFile(fname, []byte(tun.(*NativeTun).name+"\n"), 0400)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +140,7 @@ func CreateTUN(name string, mtu int) (TUNDevice, error) {
|
||||
|
||||
func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
|
||||
tun := &nativeTun{
|
||||
tun := &NativeTun{
|
||||
tunFile: file,
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
@@ -167,12 +164,6 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.rwcancel, err = rwcancel.NewRWCancel(int(file.Fd()))
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tun.routeSocket, err = unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, unix.AF_UNSPEC)
|
||||
if err != nil {
|
||||
tun.tunFile.Close()
|
||||
@@ -190,7 +181,7 @@ func CreateTUNFromFile(file *os.File, mtu int) (TUNDevice, error) {
|
||||
return tun, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Name() (string, error) {
|
||||
func (tun *NativeTun) Name() (string, error) {
|
||||
gostat, err := tun.tunFile.Stat()
|
||||
if err != nil {
|
||||
tun.name = ""
|
||||
@@ -201,15 +192,15 @@ func (tun *nativeTun) Name() (string, error) {
|
||||
return tun.name, nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) File() *os.File {
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
return tun.tunFile
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Events() chan TUNEvent {
|
||||
func (tun *NativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
@@ -223,19 +214,7 @@ func (tun *nativeTun) doRead(buff []byte, offset int) (int, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
for {
|
||||
n, err := tun.doRead(buff, offset)
|
||||
if err == nil || !rwcancel.RetryAfterError(err) {
|
||||
return n, err
|
||||
}
|
||||
if !tun.rwcancel.ReadyRead() {
|
||||
return 0, errors.New("tun device closed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
|
||||
// reserve space for header
|
||||
|
||||
@@ -258,13 +237,17 @@ func (tun *nativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
return tun.tunFile.Write(buff)
|
||||
}
|
||||
|
||||
func (tun *nativeTun) Close() error {
|
||||
var err3 error
|
||||
err1 := tun.rwcancel.Cancel()
|
||||
err2 := tun.tunFile.Close()
|
||||
func (tun *NativeTun) Flush() error {
|
||||
//TODO: can flushing be implemented by buffering and using sendmmsg?
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Close() error {
|
||||
var err2 error
|
||||
err1 := tun.tunFile.Close()
|
||||
if tun.routeSocket != -1 {
|
||||
unix.Shutdown(tun.routeSocket, unix.SHUT_RDWR)
|
||||
err3 = unix.Close(tun.routeSocket)
|
||||
err2 = unix.Close(tun.routeSocket)
|
||||
tun.routeSocket = -1
|
||||
} else if tun.events != nil {
|
||||
close(tun.events)
|
||||
@@ -272,13 +255,10 @@ func (tun *nativeTun) Close() error {
|
||||
if err1 != nil {
|
||||
return err1
|
||||
}
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
return err3
|
||||
}
|
||||
|
||||
func (tun *nativeTun) setMTU(n int) error {
|
||||
func (tun *NativeTun) setMTU(n int) error {
|
||||
// open datagram socket
|
||||
|
||||
var fd int
|
||||
@@ -315,7 +295,7 @@ func (tun *nativeTun) setMTU(n int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *nativeTun) MTU() (int, error) {
|
||||
func (tun *NativeTun) MTU() (int, error) {
|
||||
// open datagram socket
|
||||
|
||||
fd, err := unix.Socket(
|
||||
|
||||
373
tun/tun_windows.go
Normal file
373
tun/tun_windows.go
Normal file
@@ -0,0 +1,373 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2018-2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package tun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/tun/wintun"
|
||||
)
|
||||
|
||||
const (
|
||||
packetExchangeMax uint32 = 256 // Number of packets that may be written at a time
|
||||
packetExchangeAlignment uint32 = 16 // Number of bytes packets are aligned to in exchange buffers
|
||||
packetSizeMax uint32 = 0xf000 - packetExchangeAlignment // Maximum packet size
|
||||
packetExchangeSize uint32 = 0x100000 // Exchange buffer size (defaults to 1MiB)
|
||||
retryRate = 4 // Number of retries per second to reopen device pipe
|
||||
retryTimeout = 30 // Number of seconds to tolerate adapter unavailable
|
||||
)
|
||||
|
||||
type exchgBufRead struct {
|
||||
data [packetExchangeSize]byte
|
||||
offset uint32
|
||||
avail uint32
|
||||
}
|
||||
|
||||
type exchgBufWrite struct {
|
||||
data [packetExchangeSize]byte
|
||||
offset uint32
|
||||
packetNum uint32
|
||||
}
|
||||
|
||||
type NativeTun struct {
|
||||
wt *wintun.Wintun
|
||||
tunFileRead *os.File
|
||||
tunFileWrite *os.File
|
||||
tunLock sync.Mutex
|
||||
close bool
|
||||
rdBuff *exchgBufRead
|
||||
wrBuff *exchgBufWrite
|
||||
events chan TUNEvent
|
||||
errors chan error
|
||||
forcedMtu int
|
||||
}
|
||||
|
||||
func packetAlign(size uint32) uint32 {
|
||||
return (size + (packetExchangeAlignment - 1)) &^ (packetExchangeAlignment - 1)
|
||||
}
|
||||
|
||||
//
|
||||
// CreateTUN creates a Wintun adapter with the given name. Should a Wintun
|
||||
// adapter with the same name exist, it is reused.
|
||||
//
|
||||
func CreateTUN(ifname string) (TUNDevice, error) {
|
||||
// Does an interface with this name already exist?
|
||||
wt, err := wintun.GetInterface(ifname, 0)
|
||||
if wt == nil {
|
||||
// Interface does not exist or an error occured. Create one.
|
||||
wt, _, err = wintun.CreateInterface("WireGuard Tunnel Adapter", 0)
|
||||
if err != nil {
|
||||
return nil, errors.New("Creating Wintun adapter failed: " + err.Error())
|
||||
}
|
||||
} else if err != nil {
|
||||
// Foreign interface with the same name found.
|
||||
// We could create a Wintun interface under a temporary name. But, should our
|
||||
// proces die without deleting this interface first, the interface would remain
|
||||
// orphaned.
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = wt.SetInterfaceName(ifname)
|
||||
if err != nil {
|
||||
wt.DeleteInterface(0)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = wt.FlushInterface()
|
||||
if err != nil {
|
||||
wt.DeleteInterface(0)
|
||||
return nil, errors.New("Flushing interface failed: " + err.Error())
|
||||
}
|
||||
|
||||
return &NativeTun{
|
||||
wt: wt,
|
||||
rdBuff: &exchgBufRead{},
|
||||
wrBuff: &exchgBufWrite{},
|
||||
events: make(chan TUNEvent, 10),
|
||||
errors: make(chan error, 1),
|
||||
forcedMtu: 1500,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) openTUN() error {
|
||||
retries := retryTimeout * retryRate
|
||||
if tun.close {
|
||||
return os.ErrClosed
|
||||
}
|
||||
|
||||
var err error
|
||||
name := tun.wt.DataFileName()
|
||||
for tun.tunFileRead == nil {
|
||||
tun.tunFileRead, err = os.OpenFile(name, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
if retries > 0 && !tun.close {
|
||||
time.Sleep(time.Second / retryRate)
|
||||
retries--
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
for tun.tunFileWrite == nil {
|
||||
tun.tunFileWrite, err = os.OpenFile(name, os.O_WRONLY, 0)
|
||||
if err != nil {
|
||||
if retries > 0 && !tun.close {
|
||||
time.Sleep(time.Second / retryRate)
|
||||
retries--
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) closeTUN() (err error) {
|
||||
for tun.tunFileRead != nil {
|
||||
tun.tunLock.Lock()
|
||||
if tun.tunFileRead == nil {
|
||||
tun.tunLock.Unlock()
|
||||
break
|
||||
}
|
||||
t := tun.tunFileRead
|
||||
tun.tunFileRead = nil
|
||||
windows.CancelIoEx(windows.Handle(t.Fd()), nil)
|
||||
err = t.Close()
|
||||
tun.tunLock.Unlock()
|
||||
break
|
||||
}
|
||||
for tun.tunFileWrite != nil {
|
||||
tun.tunLock.Lock()
|
||||
if tun.tunFileWrite == nil {
|
||||
tun.tunLock.Unlock()
|
||||
break
|
||||
}
|
||||
t := tun.tunFileWrite
|
||||
tun.tunFileWrite = nil
|
||||
windows.CancelIoEx(windows.Handle(t.Fd()), nil)
|
||||
err2 := t.Close()
|
||||
tun.tunLock.Unlock()
|
||||
if err == nil {
|
||||
err = err2
|
||||
}
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (tun *NativeTun) getTUN() (read *os.File, write *os.File, err error) {
|
||||
read, write = tun.tunFileRead, tun.tunFileWrite
|
||||
if read == nil || write == nil {
|
||||
read, write = nil, nil
|
||||
tun.tunLock.Lock()
|
||||
if tun.tunFileRead != nil && tun.tunFileWrite != nil {
|
||||
read, write = tun.tunFileRead, tun.tunFileWrite
|
||||
tun.tunLock.Unlock()
|
||||
return
|
||||
}
|
||||
err = tun.closeTUN()
|
||||
if err != nil {
|
||||
tun.tunLock.Unlock()
|
||||
return
|
||||
}
|
||||
err = tun.openTUN()
|
||||
if err == nil {
|
||||
read, write = tun.tunFileRead, tun.tunFileWrite
|
||||
}
|
||||
tun.tunLock.Unlock()
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Name() (string, error) {
|
||||
return tun.wt.GetInterfaceName()
|
||||
}
|
||||
|
||||
func (tun *NativeTun) File() *os.File {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Events() chan TUNEvent {
|
||||
return tun.events
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Close() error {
|
||||
tun.close = true
|
||||
err1 := tun.closeTUN()
|
||||
|
||||
if tun.events != nil {
|
||||
close(tun.events)
|
||||
}
|
||||
|
||||
_, _, err2 := tun.wt.DeleteInterface(0)
|
||||
if err1 == nil {
|
||||
err1 = err2
|
||||
}
|
||||
|
||||
return err1
|
||||
}
|
||||
|
||||
func (tun *NativeTun) MTU() (int, error) {
|
||||
return tun.forcedMtu, nil
|
||||
}
|
||||
|
||||
//TODO: This is a temporary hack. We really need to be monitoring the interface in real time and adapting to MTU changes.
|
||||
func (tun *NativeTun) ForceMtu(mtu int) {
|
||||
tun.forcedMtu = mtu
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Read(buff []byte, offset int) (int, error) {
|
||||
select {
|
||||
case err := <-tun.errors:
|
||||
return 0, err
|
||||
default:
|
||||
}
|
||||
|
||||
for {
|
||||
if tun.rdBuff.offset+packetExchangeAlignment <= tun.rdBuff.avail {
|
||||
// Get packet from the exchange buffer.
|
||||
packet := tun.rdBuff.data[tun.rdBuff.offset:]
|
||||
size := *(*uint32)(unsafe.Pointer(&packet[0]))
|
||||
pSize := packetAlign(packetExchangeAlignment + size)
|
||||
if packetSizeMax < size || tun.rdBuff.avail < tun.rdBuff.offset+pSize {
|
||||
// Invalid packet size.
|
||||
tun.rdBuff.avail = 0
|
||||
continue
|
||||
}
|
||||
packet = packet[packetExchangeAlignment : packetExchangeAlignment+size]
|
||||
|
||||
// Copy data.
|
||||
copy(buff[offset:], packet)
|
||||
tun.rdBuff.offset += pSize
|
||||
return int(size), nil
|
||||
}
|
||||
|
||||
// Get TUN data pipe.
|
||||
file, _, err := tun.getTUN()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// Fill queue.
|
||||
retries := 1000
|
||||
for {
|
||||
n, err := file.Read(tun.rdBuff.data[:])
|
||||
if err != nil {
|
||||
tun.rdBuff.offset = 0
|
||||
tun.rdBuff.avail = 0
|
||||
pe, ok := err.(*os.PathError)
|
||||
if tun.close {
|
||||
return 0, os.ErrClosed
|
||||
}
|
||||
if retries > 0 && ok && pe.Err == windows.ERROR_OPERATION_ABORTED {
|
||||
retries--
|
||||
continue
|
||||
}
|
||||
if ok && pe.Err == syscall.Errno(6) /*windows.ERROR_INVALID_HANDLE*/ {
|
||||
tun.closeTUN()
|
||||
break
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
tun.rdBuff.offset = 0
|
||||
tun.rdBuff.avail = uint32(n)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: flush() and putTunPacket() assume the caller comes only from a single thread; there's no locking.
|
||||
|
||||
func (tun *NativeTun) Flush() error {
|
||||
if tun.wrBuff.offset == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
for {
|
||||
// Get TUN data pipe.
|
||||
_, file, err := tun.getTUN()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Flush write buffer.
|
||||
retries := retryTimeout * retryRate
|
||||
for {
|
||||
_, err = file.Write(tun.wrBuff.data[:tun.wrBuff.offset])
|
||||
tun.wrBuff.packetNum = 0
|
||||
tun.wrBuff.offset = 0
|
||||
if err != nil {
|
||||
pe, ok := err.(*os.PathError)
|
||||
if tun.close {
|
||||
return os.ErrClosed
|
||||
}
|
||||
if retries > 0 && ok && pe.Err == windows.ERROR_OPERATION_ABORTED {
|
||||
time.Sleep(time.Second / retryRate)
|
||||
retries--
|
||||
continue
|
||||
}
|
||||
if ok && pe.Err == syscall.Errno(6) /*windows.ERROR_INVALID_HANDLE*/ {
|
||||
tun.closeTUN()
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (tun *NativeTun) putTunPacket(buff []byte) error {
|
||||
size := uint32(len(buff))
|
||||
if size == 0 {
|
||||
return errors.New("Empty packet")
|
||||
}
|
||||
if size > packetSizeMax {
|
||||
return errors.New("Packet too big")
|
||||
}
|
||||
pSize := packetAlign(packetExchangeAlignment + size)
|
||||
|
||||
if tun.wrBuff.packetNum >= packetExchangeMax || tun.wrBuff.offset+pSize >= packetExchangeSize {
|
||||
// Exchange buffer is full -> flush first.
|
||||
err := tun.Flush()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Write packet to the exchange buffer.
|
||||
packet := tun.wrBuff.data[tun.wrBuff.offset : tun.wrBuff.offset+pSize]
|
||||
*(*uint32)(unsafe.Pointer(&packet[0])) = size
|
||||
packet = packet[packetExchangeAlignment : packetExchangeAlignment+size]
|
||||
copy(packet, buff)
|
||||
|
||||
tun.wrBuff.packetNum++
|
||||
tun.wrBuff.offset += pSize
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tun *NativeTun) Write(buff []byte, offset int) (int, error) {
|
||||
err := tun.putTunPacket(buff[offset:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(buff) - offset, nil
|
||||
}
|
||||
|
||||
//
|
||||
// GUID returns Windows adapter instance ID.
|
||||
//
|
||||
func (tun *NativeTun) GUID() windows.GUID {
|
||||
return tun.wt.CfgInstanceID
|
||||
}
|
||||
44
tun/wintun/guid/guid_windows.go
Normal file
44
tun/wintun/guid/guid_windows.go
Normal file
@@ -0,0 +1,44 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package guid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
//sys clsidFromString(lpsz *uint16, pclsid *windows.GUID) (hr int32) = ole32.CLSIDFromString
|
||||
|
||||
//
|
||||
// FromString parses "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" string to GUID.
|
||||
//
|
||||
func FromString(str string) (*windows.GUID, error) {
|
||||
strUTF16, err := syscall.UTF16PtrFromString(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
guid := &windows.GUID{}
|
||||
|
||||
hr := clsidFromString(strUTF16, guid)
|
||||
if hr < 0 {
|
||||
return nil, syscall.Errno(hr)
|
||||
}
|
||||
|
||||
return guid, nil
|
||||
}
|
||||
|
||||
//
|
||||
// ToString function converts GUID to string
|
||||
// "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}".
|
||||
//
|
||||
// The resulting string is uppercase.
|
||||
//
|
||||
func ToString(guid *windows.GUID) string {
|
||||
return fmt.Sprintf("{%06X-%04X-%04X-%04X-%012X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[:2], guid.Data4[2:])
|
||||
}
|
||||
8
tun/wintun/guid/mksyscall.go
Normal file
8
tun/wintun/guid/mksyscall.go
Normal file
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package guid
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zguid_windows.go guid_windows.go
|
||||
49
tun/wintun/guid/zguid_windows.go
Normal file
49
tun/wintun/guid/zguid_windows.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package guid
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modole32 = windows.NewLazySystemDLL("ole32.dll")
|
||||
|
||||
procCLSIDFromString = modole32.NewProc("CLSIDFromString")
|
||||
)
|
||||
|
||||
func clsidFromString(lpsz *uint16, pclsid *windows.GUID) (hr int32) {
|
||||
r0, _, _ := syscall.Syscall(procCLSIDFromString.Addr(), 2, uintptr(unsafe.Pointer(lpsz)), uintptr(unsafe.Pointer(pclsid)), 0)
|
||||
hr = int32(r0)
|
||||
return
|
||||
}
|
||||
32
tun/wintun/netshell/netshell_windows.go
Normal file
32
tun/wintun/netshell/netshell_windows.go
Normal file
@@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package netshell
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var (
|
||||
modnetshell = windows.NewLazySystemDLL("netshell.dll")
|
||||
procHrRenameConnection = modnetshell.NewProc("HrRenameConnection")
|
||||
)
|
||||
|
||||
func HrRenameConnection(guid *windows.GUID, newName *uint16) (err error) {
|
||||
err = procHrRenameConnection.Find()
|
||||
if err != nil {
|
||||
// Missing from servercore, so we can't presume it's always there.
|
||||
return
|
||||
}
|
||||
|
||||
ret, _, _ := syscall.Syscall(procHrRenameConnection.Addr(), 2, uintptr(unsafe.Pointer(guid)), uintptr(unsafe.Pointer(newName)), 0)
|
||||
if ret != 0 {
|
||||
err = syscall.Errno(ret)
|
||||
}
|
||||
return
|
||||
}
|
||||
42
tun/wintun/registryhacks_windows.go
Normal file
42
tun/wintun/registryhacks_windows.go
Normal file
@@ -0,0 +1,42 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package wintun
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/windows/registry"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
numRetries = 25
|
||||
retryTimeout = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
func registryOpenKeyRetry(k registry.Key, path string, access uint32) (key registry.Key, err error) {
|
||||
for i := 0; i < numRetries; i++ {
|
||||
key, err = registry.OpenKey(k, path, access)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if i != numRetries - 1 {
|
||||
time.Sleep(retryTimeout)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func keyGetStringValueRetry(k registry.Key, name string) (val string, valtype uint32, err error) {
|
||||
for i := 0; i < numRetries; i++ {
|
||||
val, valtype, err = k.GetStringValue(name)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
if i != numRetries - 1 {
|
||||
time.Sleep(retryTimeout)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
8
tun/wintun/setupapi/mksyscall.go
Normal file
8
tun/wintun/setupapi/mksyscall.go
Normal file
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package setupapi
|
||||
|
||||
//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsetupapi_windows.go setupapi_windows.go
|
||||
458
tun/wintun/setupapi/setupapi_windows.go
Normal file
458
tun/wintun/setupapi/setupapi_windows.go
Normal file
@@ -0,0 +1,458 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package setupapi
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
)
|
||||
|
||||
//sys setupDiCreateDeviceInfoListEx(classGUID *windows.GUID, hwndParent uintptr, machineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(windows.InvalidHandle)] = setupapi.SetupDiCreateDeviceInfoListExW
|
||||
|
||||
// SetupDiCreateDeviceInfoListEx function creates an empty device information set on a remote or a local computer and optionally associates the set with a device setup class.
|
||||
func SetupDiCreateDeviceInfoListEx(classGUID *windows.GUID, hwndParent uintptr, machineName string) (deviceInfoSet DevInfo, err error) {
|
||||
var machineNameUTF16 *uint16
|
||||
if machineName != "" {
|
||||
machineNameUTF16, err = syscall.UTF16PtrFromString(machineName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return setupDiCreateDeviceInfoListEx(classGUID, hwndParent, machineNameUTF16, 0)
|
||||
}
|
||||
|
||||
//sys setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailData *DevInfoListDetailData) (err error) = setupapi.SetupDiGetDeviceInfoListDetailW
|
||||
|
||||
// SetupDiGetDeviceInfoListDetail function retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name.
|
||||
func SetupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo) (deviceInfoSetDetailData *DevInfoListDetailData, err error) {
|
||||
data := &DevInfoListDetailData{}
|
||||
data.size = uint32(unsafe.Sizeof(*data))
|
||||
|
||||
return data, setupDiGetDeviceInfoListDetail(deviceInfoSet, data)
|
||||
}
|
||||
|
||||
// GetDeviceInfoListDetail method retrieves information associated with a device information set including the class GUID, remote computer handle, and remote computer name.
|
||||
func (deviceInfoSet DevInfo) GetDeviceInfoListDetail() (*DevInfoListDetailData, error) {
|
||||
return SetupDiGetDeviceInfoListDetail(deviceInfoSet)
|
||||
}
|
||||
|
||||
//sys setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUID *windows.GUID, DeviceDescription *uint16, hwndParent uintptr, CreationFlags DICD, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiCreateDeviceInfoW
|
||||
|
||||
// SetupDiCreateDeviceInfo function creates a new device information element and adds it as a new member to the specified device information set.
|
||||
func SetupDiCreateDeviceInfo(deviceInfoSet DevInfo, deviceName string, classGUID *windows.GUID, deviceDescription string, hwndParent uintptr, creationFlags DICD) (deviceInfoData *DevInfoData, err error) {
|
||||
deviceNameUTF16, err := syscall.UTF16PtrFromString(deviceName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var deviceDescriptionUTF16 *uint16
|
||||
if deviceDescription != "" {
|
||||
deviceDescriptionUTF16, err = syscall.UTF16PtrFromString(deviceDescription)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
data := &DevInfoData{}
|
||||
data.size = uint32(unsafe.Sizeof(*data))
|
||||
|
||||
return data, setupDiCreateDeviceInfo(deviceInfoSet, deviceNameUTF16, classGUID, deviceDescriptionUTF16, hwndParent, creationFlags, data)
|
||||
}
|
||||
|
||||
// CreateDeviceInfo method creates a new device information element and adds it as a new member to the specified device information set.
|
||||
func (deviceInfoSet DevInfo) CreateDeviceInfo(deviceName string, classGUID *windows.GUID, deviceDescription string, hwndParent uintptr, creationFlags DICD) (*DevInfoData, error) {
|
||||
return SetupDiCreateDeviceInfo(deviceInfoSet, deviceName, classGUID, deviceDescription, hwndParent, creationFlags)
|
||||
}
|
||||
|
||||
//sys setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiEnumDeviceInfo
|
||||
|
||||
// SetupDiEnumDeviceInfo function returns a DevInfoData structure that specifies a device information element in a device information set.
|
||||
func SetupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex int) (*DevInfoData, error) {
|
||||
data := &DevInfoData{}
|
||||
data.size = uint32(unsafe.Sizeof(*data))
|
||||
|
||||
return data, setupDiEnumDeviceInfo(deviceInfoSet, uint32(memberIndex), data)
|
||||
}
|
||||
|
||||
// EnumDeviceInfo method returns a DevInfoData structure that specifies a device information element in a device information set.
|
||||
func (deviceInfoSet DevInfo) EnumDeviceInfo(memberIndex int) (*DevInfoData, error) {
|
||||
return SetupDiEnumDeviceInfo(deviceInfoSet, memberIndex)
|
||||
}
|
||||
|
||||
// SetupDiDestroyDeviceInfoList function deletes a device information set and frees all associated memory.
|
||||
//sys SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) = setupapi.SetupDiDestroyDeviceInfoList
|
||||
|
||||
// Close method deletes a device information set and frees all associated memory.
|
||||
func (deviceInfoSet DevInfo) Close() error {
|
||||
return SetupDiDestroyDeviceInfoList(deviceInfoSet)
|
||||
}
|
||||
|
||||
//sys SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) = setupapi.SetupDiBuildDriverInfoList
|
||||
|
||||
// BuildDriverInfoList method builds a list of drivers that is associated with a specific device or with the global class driver list for a device information set.
|
||||
func (deviceInfoSet DevInfo) BuildDriverInfoList(deviceInfoData *DevInfoData, driverType SPDIT) error {
|
||||
return SetupDiBuildDriverInfoList(deviceInfoSet, deviceInfoData, driverType)
|
||||
}
|
||||
|
||||
//sys SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) = setupapi.SetupDiCancelDriverInfoSearch
|
||||
|
||||
// CancelDriverInfoSearch method cancels a driver list search that is currently in progress in a different thread.
|
||||
func (deviceInfoSet DevInfo) CancelDriverInfoSearch() error {
|
||||
return SetupDiCancelDriverInfoSearch(deviceInfoSet)
|
||||
}
|
||||
|
||||
//sys setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex uint32, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiEnumDriverInfoW
|
||||
|
||||
// SetupDiEnumDriverInfo function enumerates the members of a driver list.
|
||||
func SetupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex int) (*DrvInfoData, error) {
|
||||
data := &DrvInfoData{}
|
||||
data.size = uint32(unsafe.Sizeof(*data))
|
||||
|
||||
return data, setupDiEnumDriverInfo(deviceInfoSet, deviceInfoData, driverType, uint32(memberIndex), data)
|
||||
}
|
||||
|
||||
// EnumDriverInfo method enumerates the members of a driver list.
|
||||
func (deviceInfoSet DevInfo) EnumDriverInfo(deviceInfoData *DevInfoData, driverType SPDIT, memberIndex int) (*DrvInfoData, error) {
|
||||
return SetupDiEnumDriverInfo(deviceInfoSet, deviceInfoData, driverType, memberIndex)
|
||||
}
|
||||
|
||||
//sys setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiGetSelectedDriverW
|
||||
|
||||
// SetupDiGetSelectedDriver function retrieves the selected driver for a device information set or a particular device information element.
|
||||
func SetupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (*DrvInfoData, error) {
|
||||
data := &DrvInfoData{}
|
||||
data.size = uint32(unsafe.Sizeof(*data))
|
||||
|
||||
return data, setupDiGetSelectedDriver(deviceInfoSet, deviceInfoData, data)
|
||||
}
|
||||
|
||||
// GetSelectedDriver method retrieves the selected driver for a device information set or a particular device information element.
|
||||
func (deviceInfoSet DevInfo) GetSelectedDriver(deviceInfoData *DevInfoData) (*DrvInfoData, error) {
|
||||
return SetupDiGetSelectedDriver(deviceInfoSet, deviceInfoData)
|
||||
}
|
||||
|
||||
//sys SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) = setupapi.SetupDiSetSelectedDriverW
|
||||
|
||||
// SetSelectedDriver method sets, or resets, the selected driver for a device information element or the selected class driver for a device information set.
|
||||
func (deviceInfoSet DevInfo) SetSelectedDriver(deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) error {
|
||||
return SetupDiSetSelectedDriver(deviceInfoSet, deviceInfoData, driverInfoData)
|
||||
}
|
||||
|
||||
//sys setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData, driverInfoDetailData *DrvInfoDetailData, driverInfoDetailDataSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetDriverInfoDetailW
|
||||
|
||||
// SetupDiGetDriverInfoDetail function retrieves driver information detail for a device information set or a particular device information element in the device information set.
|
||||
func SetupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (*DrvInfoDetailData, error) {
|
||||
const bufCapacity = 0x800
|
||||
buf := [bufCapacity]byte{}
|
||||
var bufLen uint32
|
||||
|
||||
data := (*DrvInfoDetailData)(unsafe.Pointer(&buf[0]))
|
||||
data.size = uint32(unsafe.Sizeof(*data))
|
||||
|
||||
err := setupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData, data, bufCapacity, &bufLen)
|
||||
if err == nil {
|
||||
// The buffer was was sufficiently big.
|
||||
data.size = bufLen
|
||||
return data, nil
|
||||
}
|
||||
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_INSUFFICIENT_BUFFER {
|
||||
// The buffer was too small. Now that we got the required size, create another one big enough and retry.
|
||||
buf := make([]byte, bufLen)
|
||||
data := (*DrvInfoDetailData)(unsafe.Pointer(&buf[0]))
|
||||
data.size = uint32(unsafe.Sizeof(*data))
|
||||
|
||||
err = setupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData, data, bufLen, &bufLen)
|
||||
if err == nil {
|
||||
data.size = bufLen
|
||||
return data, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// GetDriverInfoDetail method retrieves driver information detail for a device information set or a particular device information element in the device information set.
|
||||
func (deviceInfoSet DevInfo) GetDriverInfoDetail(deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (*DrvInfoDetailData, error) {
|
||||
return SetupDiGetDriverInfoDetail(deviceInfoSet, deviceInfoData, driverInfoData)
|
||||
}
|
||||
|
||||
//sys SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) = setupapi.SetupDiDestroyDriverInfoList
|
||||
|
||||
// DestroyDriverInfoList method deletes a driver list.
|
||||
func (deviceInfoSet DevInfo) DestroyDriverInfoList(deviceInfoData *DevInfoData, driverType SPDIT) error {
|
||||
return SetupDiDestroyDriverInfoList(deviceInfoSet, deviceInfoData, driverType)
|
||||
}
|
||||
|
||||
//sys setupDiGetClassDevsEx(classGUID *windows.GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, deviceInfoSet DevInfo, machineName *uint16, reserved uintptr) (handle DevInfo, err error) [failretval==DevInfo(windows.InvalidHandle)] = setupapi.SetupDiGetClassDevsExW
|
||||
|
||||
// SetupDiGetClassDevsEx function returns a handle to a device information set that contains requested device information elements for a local or a remote computer.
|
||||
func SetupDiGetClassDevsEx(classGUID *windows.GUID, enumerator string, hwndParent uintptr, flags DIGCF, deviceInfoSet DevInfo, machineName string) (handle DevInfo, err error) {
|
||||
var enumeratorUTF16 *uint16
|
||||
if enumerator != "" {
|
||||
enumeratorUTF16, err = syscall.UTF16PtrFromString(enumerator)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
var machineNameUTF16 *uint16
|
||||
if machineName != "" {
|
||||
machineNameUTF16, err = syscall.UTF16PtrFromString(machineName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return setupDiGetClassDevsEx(classGUID, enumeratorUTF16, hwndParent, flags, deviceInfoSet, machineNameUTF16, 0)
|
||||
}
|
||||
|
||||
// SetupDiCallClassInstaller function calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code).
|
||||
//sys SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiCallClassInstaller
|
||||
|
||||
// CallClassInstaller member calls the appropriate class installer, and any registered co-installers, with the specified installation request (DIF code).
|
||||
func (deviceInfoSet DevInfo) CallClassInstaller(installFunction DI_FUNCTION, deviceInfoData *DevInfoData) error {
|
||||
return SetupDiCallClassInstaller(installFunction, deviceInfoSet, deviceInfoData)
|
||||
}
|
||||
|
||||
//sys setupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key windows.Handle, err error) [failretval==windows.InvalidHandle] = setupapi.SetupDiOpenDevRegKey
|
||||
|
||||
// SetupDiOpenDevRegKey function opens a registry key for device-specific configuration information.
|
||||
func SetupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, scope DICS_FLAG, hwProfile uint32, keyType DIREG, samDesired uint32) (registry.Key, error) {
|
||||
handle, err := setupDiOpenDevRegKey(deviceInfoSet, deviceInfoData, scope, hwProfile, keyType, samDesired)
|
||||
return registry.Key(handle), err
|
||||
}
|
||||
|
||||
// OpenDevRegKey method opens a registry key for device-specific configuration information.
|
||||
func (deviceInfoSet DevInfo) OpenDevRegKey(DeviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (registry.Key, error) {
|
||||
return SetupDiOpenDevRegKey(deviceInfoSet, DeviceInfoData, Scope, HwProfile, KeyType, samDesired)
|
||||
}
|
||||
|
||||
//sys setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyRegDataType *uint32, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetDeviceRegistryPropertyW
|
||||
|
||||
// SetupDiGetDeviceRegistryProperty function retrieves a specified Plug and Play device property.
|
||||
func SetupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP) (value interface{}, err error) {
|
||||
buf := make([]byte, 0x100)
|
||||
var dataType, bufLen uint32
|
||||
err = setupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &dataType, &buf[0], uint32(cap(buf)), &bufLen)
|
||||
if err == nil {
|
||||
// The buffer was sufficiently big.
|
||||
return getRegistryValue(buf[:bufLen], dataType)
|
||||
}
|
||||
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_INSUFFICIENT_BUFFER {
|
||||
// The buffer was too small. Now that we got the required size, create another one big enough and retry.
|
||||
buf = make([]byte, bufLen)
|
||||
err = setupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &dataType, &buf[0], uint32(cap(buf)), &bufLen)
|
||||
if err == nil {
|
||||
return getRegistryValue(buf[:bufLen], dataType)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getRegistryValue(buf []byte, dataType uint32) (interface{}, error) {
|
||||
switch dataType {
|
||||
case windows.REG_SZ:
|
||||
return windows.UTF16ToString(BufToUTF16(buf)), nil
|
||||
case windows.REG_EXPAND_SZ:
|
||||
return registry.ExpandString(windows.UTF16ToString(BufToUTF16(buf)))
|
||||
case windows.REG_BINARY:
|
||||
return buf, nil
|
||||
case windows.REG_DWORD_LITTLE_ENDIAN:
|
||||
return binary.LittleEndian.Uint32(buf), nil
|
||||
case windows.REG_DWORD_BIG_ENDIAN:
|
||||
return binary.BigEndian.Uint32(buf), nil
|
||||
case windows.REG_MULTI_SZ:
|
||||
bufW := BufToUTF16(buf)
|
||||
a := []string{}
|
||||
for i := 0; i < len(bufW); {
|
||||
j := i + wcslen(bufW[i:])
|
||||
if i < j {
|
||||
a = append(a, windows.UTF16ToString(bufW[i:j]))
|
||||
}
|
||||
i = j + 1
|
||||
}
|
||||
return a, nil
|
||||
case windows.REG_QWORD_LITTLE_ENDIAN:
|
||||
return binary.LittleEndian.Uint64(buf), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported registry value type: %v", dataType)
|
||||
}
|
||||
}
|
||||
|
||||
// BufToUTF16 function reinterprets []byte buffer as []uint16
|
||||
func BufToUTF16(buf []byte) []uint16 {
|
||||
sl := struct {
|
||||
addr *uint16
|
||||
len int
|
||||
cap int
|
||||
}{(*uint16)(unsafe.Pointer(&buf[0])), len(buf) / 2, cap(buf) / 2}
|
||||
return *(*[]uint16)(unsafe.Pointer(&sl))
|
||||
}
|
||||
|
||||
// UTF16ToBuf function reinterprets []uint16 as []byte
|
||||
func UTF16ToBuf(buf []uint16) []byte {
|
||||
sl := struct {
|
||||
addr *byte
|
||||
len int
|
||||
cap int
|
||||
}{(*byte)(unsafe.Pointer(&buf[0])), len(buf) * 2, cap(buf) * 2}
|
||||
return *(*[]byte)(unsafe.Pointer(&sl))
|
||||
}
|
||||
|
||||
func wcslen(str []uint16) int {
|
||||
for i := 0; i < len(str); i++ {
|
||||
if str[i] == 0 {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return len(str)
|
||||
}
|
||||
|
||||
// GetDeviceRegistryProperty method retrieves a specified Plug and Play device property.
|
||||
func (deviceInfoSet DevInfo) GetDeviceRegistryProperty(deviceInfoData *DevInfoData, property SPDRP) (interface{}, error) {
|
||||
return SetupDiGetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property)
|
||||
}
|
||||
|
||||
//sys setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffer *byte, propertyBufferSize uint32) (err error) = setupapi.SetupDiSetDeviceRegistryPropertyW
|
||||
|
||||
// SetupDiSetDeviceRegistryProperty function sets a Plug and Play device property for a device.
|
||||
func SetupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffers []byte) error {
|
||||
return setupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, &propertyBuffers[0], uint32(len(propertyBuffers)))
|
||||
}
|
||||
|
||||
// SetDeviceRegistryProperty function sets a Plug and Play device property for a device.
|
||||
func (deviceInfoSet DevInfo) SetDeviceRegistryProperty(deviceInfoData *DevInfoData, property SPDRP, propertyBuffers []byte) error {
|
||||
return SetupDiSetDeviceRegistryProperty(deviceInfoSet, deviceInfoData, property, propertyBuffers)
|
||||
}
|
||||
|
||||
//sys setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiGetDeviceInstallParamsW
|
||||
|
||||
// SetupDiGetDeviceInstallParams function retrieves device installation parameters for a device information set or a particular device information element.
|
||||
func SetupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (*DevInstallParams, error) {
|
||||
params := &DevInstallParams{}
|
||||
params.size = uint32(unsafe.Sizeof(*params))
|
||||
|
||||
return params, setupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData, params)
|
||||
}
|
||||
|
||||
// GetDeviceInstallParams method retrieves device installation parameters for a device information set or a particular device information element.
|
||||
func (deviceInfoSet DevInfo) GetDeviceInstallParams(deviceInfoData *DevInfoData) (*DevInstallParams, error) {
|
||||
return SetupDiGetDeviceInstallParams(deviceInfoSet, deviceInfoData)
|
||||
}
|
||||
|
||||
// SetupDiGetClassInstallParams function retrieves class installation parameters for a device information set or a particular device information element.
|
||||
//sys SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) (err error) = setupapi.SetupDiGetClassInstallParamsW
|
||||
|
||||
// GetClassInstallParams method retrieves class installation parameters for a device information set or a particular device information element.
|
||||
func (deviceInfoSet DevInfo) GetClassInstallParams(deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) error {
|
||||
return SetupDiGetClassInstallParams(deviceInfoSet, deviceInfoData, classInstallParams, classInstallParamsSize, requiredSize)
|
||||
}
|
||||
|
||||
//sys SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) = setupapi.SetupDiSetDeviceInstallParamsW
|
||||
|
||||
// SetDeviceInstallParams member sets device installation parameters for a device information set or a particular device information element.
|
||||
func (deviceInfoSet DevInfo) SetDeviceInstallParams(deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) error {
|
||||
return SetupDiSetDeviceInstallParams(deviceInfoSet, deviceInfoData, deviceInstallParams)
|
||||
}
|
||||
|
||||
// SetupDiSetClassInstallParams function sets or clears class install parameters for a device information set or a particular device information element.
|
||||
//sys SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) (err error) = setupapi.SetupDiSetClassInstallParamsW
|
||||
|
||||
// SetClassInstallParams method sets or clears class install parameters for a device information set or a particular device information element.
|
||||
func (deviceInfoSet DevInfo) SetClassInstallParams(deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) error {
|
||||
return SetupDiSetClassInstallParams(deviceInfoSet, deviceInfoData, classInstallParams, classInstallParamsSize)
|
||||
}
|
||||
|
||||
//sys setupDiClassNameFromGuidEx(classGUID *windows.GUID, className *uint16, classNameSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) = setupapi.SetupDiClassNameFromGuidExW
|
||||
|
||||
// SetupDiClassNameFromGuidEx function retrieves the class name associated with a class GUID. The class can be installed on a local or remote computer.
|
||||
func SetupDiClassNameFromGuidEx(classGUID *windows.GUID, machineName string) (className string, err error) {
|
||||
var classNameUTF16 [MAX_CLASS_NAME_LEN]uint16
|
||||
|
||||
var machineNameUTF16 *uint16
|
||||
if machineName != "" {
|
||||
machineNameUTF16, err = syscall.UTF16PtrFromString(machineName)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = setupDiClassNameFromGuidEx(classGUID, &classNameUTF16[0], MAX_CLASS_NAME_LEN, nil, machineNameUTF16, 0)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
className = windows.UTF16ToString(classNameUTF16[:])
|
||||
return
|
||||
}
|
||||
|
||||
//sys setupDiClassGuidsFromNameEx(className *uint16, classGuidList *windows.GUID, classGuidListSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) = setupapi.SetupDiClassGuidsFromNameExW
|
||||
|
||||
// SetupDiClassGuidsFromNameEx function retrieves the GUIDs associated with the specified class name. This resulting list contains the classes currently installed on a local or remote computer.
|
||||
func SetupDiClassGuidsFromNameEx(className string, machineName string) ([]windows.GUID, error) {
|
||||
classNameUTF16, err := syscall.UTF16PtrFromString(className)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
const bufCapacity = 4
|
||||
var buf [bufCapacity]windows.GUID
|
||||
var bufLen uint32
|
||||
|
||||
var machineNameUTF16 *uint16
|
||||
if machineName != "" {
|
||||
machineNameUTF16, err = syscall.UTF16PtrFromString(machineName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
err = setupDiClassGuidsFromNameEx(classNameUTF16, &buf[0], bufCapacity, &bufLen, machineNameUTF16, 0)
|
||||
if err == nil {
|
||||
// The GUID array was sufficiently big. Return its slice.
|
||||
return buf[:bufLen], nil
|
||||
}
|
||||
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_INSUFFICIENT_BUFFER {
|
||||
// The GUID array was too small. Now that we got the required size, create another one big enough and retry.
|
||||
buf := make([]windows.GUID, bufLen)
|
||||
err = setupDiClassGuidsFromNameEx(classNameUTF16, &buf[0], bufLen, &bufLen, machineNameUTF16, 0)
|
||||
if err == nil {
|
||||
return buf[:bufLen], nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//sys setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiGetSelectedDevice
|
||||
|
||||
// SetupDiGetSelectedDevice function retrieves the selected device information element in a device information set.
|
||||
func SetupDiGetSelectedDevice(deviceInfoSet DevInfo) (*DevInfoData, error) {
|
||||
data := &DevInfoData{}
|
||||
data.size = uint32(unsafe.Sizeof(*data))
|
||||
|
||||
return data, setupDiGetSelectedDevice(deviceInfoSet, data)
|
||||
}
|
||||
|
||||
// GetSelectedDevice method retrieves the selected device information element in a device information set.
|
||||
func (deviceInfoSet DevInfo) GetSelectedDevice() (*DevInfoData, error) {
|
||||
return SetupDiGetSelectedDevice(deviceInfoSet)
|
||||
}
|
||||
|
||||
// SetupDiSetSelectedDevice function sets a device information element as the selected member of a device information set. This function is typically used by an installation wizard.
|
||||
//sys SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) = setupapi.SetupDiSetSelectedDevice
|
||||
|
||||
// SetSelectedDevice method sets a device information element as the selected member of a device information set. This function is typically used by an installation wizard.
|
||||
func (deviceInfoSet DevInfo) SetSelectedDevice(deviceInfoData *DevInfoData) error {
|
||||
return SetupDiSetSelectedDevice(deviceInfoSet, deviceInfoData)
|
||||
}
|
||||
483
tun/wintun/setupapi/setupapi_windows_test.go
Normal file
483
tun/wintun/setupapi/setupapi_windows_test.go
Normal file
@@ -0,0 +1,483 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package setupapi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.zx2c4.com/wireguard/tun/wintun/guid"
|
||||
)
|
||||
|
||||
var deviceClassNetGUID = windows.GUID{Data1: 0x4d36e972, Data2: 0xe325, Data3: 0x11ce, Data4: [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}
|
||||
var computerName string
|
||||
|
||||
func init() {
|
||||
computerName, _ = windows.ComputerName()
|
||||
}
|
||||
|
||||
func TestSetupDiCreateDeviceInfoListEx(t *testing.T) {
|
||||
devInfoList, err := SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, "")
|
||||
if err == nil {
|
||||
devInfoList.Close()
|
||||
} else {
|
||||
t.Errorf("Error calling SetupDiCreateDeviceInfoListEx: %s", err.Error())
|
||||
}
|
||||
|
||||
devInfoList, err = SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, computerName)
|
||||
if err == nil {
|
||||
devInfoList.Close()
|
||||
} else {
|
||||
t.Errorf("Error calling SetupDiCreateDeviceInfoListEx: %s", err.Error())
|
||||
}
|
||||
|
||||
devInfoList, err = SetupDiCreateDeviceInfoListEx(nil, 0, "")
|
||||
if err == nil {
|
||||
devInfoList.Close()
|
||||
} else {
|
||||
t.Errorf("Error calling SetupDiCreateDeviceInfoListEx(nil): %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiGetDeviceInfoListDetail(t *testing.T) {
|
||||
devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
data, err := devInfoList.GetDeviceInfoListDetail()
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetDeviceInfoListDetail: %s", err.Error())
|
||||
} else {
|
||||
if data.ClassGUID != deviceClassNetGUID {
|
||||
t.Error("SetupDiGetDeviceInfoListDetail returned different class GUID")
|
||||
}
|
||||
|
||||
if data.RemoteMachineHandle != windows.Handle(0) {
|
||||
t.Error("SetupDiGetDeviceInfoListDetail returned non-NULL remote machine handle")
|
||||
}
|
||||
|
||||
if data.GetRemoteMachineName() != "" {
|
||||
t.Error("SetupDiGetDeviceInfoListDetail returned non-NULL remote machine name")
|
||||
}
|
||||
}
|
||||
|
||||
devInfoList, err = SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), computerName)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
data, err = devInfoList.GetDeviceInfoListDetail()
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetDeviceInfoListDetail: %s", err.Error())
|
||||
} else {
|
||||
if data.ClassGUID != deviceClassNetGUID {
|
||||
t.Error("SetupDiGetDeviceInfoListDetail returned different class GUID")
|
||||
}
|
||||
|
||||
if data.RemoteMachineHandle == windows.Handle(0) {
|
||||
t.Error("SetupDiGetDeviceInfoListDetail returned NULL remote machine handle")
|
||||
}
|
||||
|
||||
if data.GetRemoteMachineName() != computerName {
|
||||
t.Error("SetupDiGetDeviceInfoListDetail returned different remote machine name")
|
||||
}
|
||||
}
|
||||
|
||||
data = &DevInfoListDetailData{}
|
||||
data.SetRemoteMachineName("foobar")
|
||||
if data.GetRemoteMachineName() != "foobar" {
|
||||
t.Error("DevInfoListDetailData.(Get|Set)RemoteMachineName() differ")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiCreateDeviceInfo(t *testing.T) {
|
||||
devInfoList, err := SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, 0, computerName)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiCreateDeviceInfoListEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
deviceClassNetName, err := SetupDiClassNameFromGuidEx(&deviceClassNetGUID, computerName)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiClassNameFromGuidEx: %s", err.Error())
|
||||
}
|
||||
|
||||
devInfoData, err := devInfoList.CreateDeviceInfo(deviceClassNetName, &deviceClassNetGUID, "This is a test device", 0, DICD_GENERATE_ID)
|
||||
if err != nil {
|
||||
// Access denied is expected, as the SetupDiCreateDeviceInfo() require elevation to succeed.
|
||||
if errWin, ok := err.(syscall.Errno); !ok || errWin != windows.ERROR_ACCESS_DENIED {
|
||||
t.Errorf("Error calling SetupDiCreateDeviceInfo: %s", err.Error())
|
||||
}
|
||||
} else if devInfoData.ClassGUID != deviceClassNetGUID {
|
||||
t.Error("SetupDiCreateDeviceInfo returned different class GUID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiEnumDeviceInfo(t *testing.T) {
|
||||
devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
for i := 0; true; i++ {
|
||||
data, err := devInfoList.EnumDeviceInfo(i)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if data.ClassGUID != deviceClassNetGUID {
|
||||
t.Error("SetupDiEnumDeviceInfo returned different class GUID")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevInfo_BuildDriverInfoList(t *testing.T) {
|
||||
devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
for i := 0; true; i++ {
|
||||
deviceData, err := devInfoList.EnumDeviceInfo(i)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
const driverType SPDIT = SPDIT_COMPATDRIVER
|
||||
err = devInfoList.BuildDriverInfoList(deviceData, driverType)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiBuildDriverInfoList: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.DestroyDriverInfoList(deviceData, driverType)
|
||||
|
||||
var selectedDriverData *DrvInfoData
|
||||
for j := 0; true; j++ {
|
||||
driverData, err := devInfoList.EnumDriverInfo(deviceData, driverType, j)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if driverData.DriverType == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !driverData.IsNewer(windows.Filetime{}, 0) {
|
||||
t.Error("Driver should have non-zero date and version")
|
||||
}
|
||||
if !driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime}, 0) {
|
||||
t.Error("Driver should have non-zero date and version")
|
||||
}
|
||||
if driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime + 1}, 0) {
|
||||
t.Error("Driver should report newer version on high-date-time")
|
||||
}
|
||||
if !driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime, LowDateTime: driverData.DriverDate.LowDateTime}, 0) {
|
||||
t.Error("Driver should have non-zero version")
|
||||
}
|
||||
if driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime, LowDateTime: driverData.DriverDate.LowDateTime + 1}, 0) {
|
||||
t.Error("Driver should report newer version on low-date-time")
|
||||
}
|
||||
if driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime, LowDateTime: driverData.DriverDate.LowDateTime}, driverData.DriverVersion) {
|
||||
t.Error("Driver should not be newer than itself")
|
||||
}
|
||||
if driverData.IsNewer(windows.Filetime{HighDateTime: driverData.DriverDate.HighDateTime, LowDateTime: driverData.DriverDate.LowDateTime}, driverData.DriverVersion+1) {
|
||||
t.Error("Driver should report newer version on version")
|
||||
}
|
||||
|
||||
err = devInfoList.SetSelectedDriver(deviceData, driverData)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiSetSelectedDriver: %s", err.Error())
|
||||
} else {
|
||||
selectedDriverData = driverData
|
||||
}
|
||||
|
||||
driverDetailData, err := devInfoList.GetDriverInfoDetail(deviceData, driverData)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetDriverInfoDetail: %s", err.Error())
|
||||
}
|
||||
|
||||
if driverDetailData.IsCompatible("foobar-aab6e3a4-144e-4786-88d3-6cec361e1edd") {
|
||||
t.Error("Invalid HWID compatibitlity reported")
|
||||
}
|
||||
if !driverDetailData.IsCompatible(strings.ToUpper(driverDetailData.GetHardwareID())) {
|
||||
t.Error("HWID compatibitlity missed")
|
||||
}
|
||||
a := driverDetailData.GetCompatIDs()
|
||||
for k := range a {
|
||||
if !driverDetailData.IsCompatible(strings.ToUpper(a[k])) {
|
||||
t.Error("HWID compatibitlity missed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectedDriverData2, err := devInfoList.GetSelectedDriver(deviceData)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetSelectedDriver: %s", err.Error())
|
||||
} else if *selectedDriverData != *selectedDriverData2 {
|
||||
t.Error("SetupDiGetSelectedDriver should return driver selected with SetupDiSetSelectedDriver")
|
||||
}
|
||||
}
|
||||
|
||||
data := &DrvInfoData{}
|
||||
data.SetDescription("foobar")
|
||||
if data.GetDescription() != "foobar" {
|
||||
t.Error("DrvInfoData.(Get|Set)Description() differ")
|
||||
}
|
||||
data.SetMfgName("foobar")
|
||||
if data.GetMfgName() != "foobar" {
|
||||
t.Error("DrvInfoData.(Get|Set)MfgName() differ")
|
||||
}
|
||||
data.SetProviderName("foobar")
|
||||
if data.GetProviderName() != "foobar" {
|
||||
t.Error("DrvInfoData.(Get|Set)ProviderName() differ")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiGetClassDevsEx(t *testing.T) {
|
||||
devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "PCI", 0, DIGCF_PRESENT, DevInfo(0), computerName)
|
||||
if err == nil {
|
||||
devInfoList.Close()
|
||||
} else {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
|
||||
devInfoList, err = SetupDiGetClassDevsEx(nil, "", 0, DIGCF_PRESENT, DevInfo(0), "")
|
||||
if err == nil {
|
||||
devInfoList.Close()
|
||||
t.Errorf("SetupDiGetClassDevsEx(nil, ...) should fail")
|
||||
} else {
|
||||
if errWin, ok := err.(syscall.Errno); !ok || errWin != 87 /*ERROR_INVALID_PARAMETER*/ {
|
||||
t.Errorf("SetupDiGetClassDevsEx(nil, ...) should fail with ERROR_INVALID_PARAMETER")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiOpenDevRegKey(t *testing.T) {
|
||||
devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
for i := 0; true; i++ {
|
||||
data, err := devInfoList.EnumDeviceInfo(i)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
key, err := devInfoList.OpenDevRegKey(data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, windows.KEY_READ)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiOpenDevRegKey: %s", err.Error())
|
||||
}
|
||||
defer key.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiGetDeviceRegistryProperty(t *testing.T) {
|
||||
devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
for i := 0; true; i++ {
|
||||
data, err := devInfoList.EnumDeviceInfo(i)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
val, err := devInfoList.GetDeviceRegistryProperty(data, SPDRP_CLASS)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_CLASS): %s", err.Error())
|
||||
} else if class, ok := val.(string); !ok || strings.ToLower(class) != "net" {
|
||||
t.Errorf("SetupDiGetDeviceRegistryProperty(SPDRP_CLASS) should return \"Net\"")
|
||||
}
|
||||
|
||||
val, err = devInfoList.GetDeviceRegistryProperty(data, SPDRP_CLASSGUID)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_CLASSGUID): %s", err.Error())
|
||||
} else if valStr, ok := val.(string); !ok {
|
||||
t.Errorf("SetupDiGetDeviceRegistryProperty(SPDRP_CLASSGUID) should return string")
|
||||
} else {
|
||||
classGUID, err := guid.FromString(valStr)
|
||||
if err != nil {
|
||||
t.Errorf("Error parsing GUID returned by SetupDiGetDeviceRegistryProperty(SPDRP_CLASSGUID): %s", err.Error())
|
||||
} else if *classGUID != deviceClassNetGUID {
|
||||
t.Errorf("SetupDiGetDeviceRegistryProperty(SPDRP_CLASSGUID) should return %x", deviceClassNetGUID)
|
||||
}
|
||||
}
|
||||
|
||||
val, err = devInfoList.GetDeviceRegistryProperty(data, SPDRP_COMPATIBLEIDS)
|
||||
if err != nil {
|
||||
// Some devices have no SPDRP_COMPATIBLEIDS.
|
||||
if errWin, ok := err.(syscall.Errno); !ok || errWin != 13 /*windows.ERROR_INVALID_DATA*/ {
|
||||
t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_COMPATIBLEIDS): %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
val, err = devInfoList.GetDeviceRegistryProperty(data, SPDRP_CONFIGFLAGS)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_CONFIGFLAGS): %s", err.Error())
|
||||
}
|
||||
|
||||
val, err = devInfoList.GetDeviceRegistryProperty(data, SPDRP_DEVICE_POWER_DATA)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetDeviceRegistryProperty(SPDRP_DEVICE_POWER_DATA): %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiGetDeviceInstallParams(t *testing.T) {
|
||||
devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
for i := 0; true; i++ {
|
||||
data, err := devInfoList.EnumDeviceInfo(i)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
_, err = devInfoList.GetDeviceInstallParams(data)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetDeviceInstallParams: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
params := &DevInstallParams{}
|
||||
params.SetDriverPath("foobar")
|
||||
if params.GetDriverPath() != "foobar" {
|
||||
t.Error("DevInstallParams.(Get|Set)DriverPath() differ")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiClassNameFromGuidEx(t *testing.T) {
|
||||
deviceClassNetName, err := SetupDiClassNameFromGuidEx(&deviceClassNetGUID, "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiClassNameFromGuidEx: %s", err.Error())
|
||||
} else if strings.ToLower(deviceClassNetName) != "net" {
|
||||
t.Errorf("SetupDiClassNameFromGuidEx(%x) should return \"Net\"", deviceClassNetGUID)
|
||||
}
|
||||
|
||||
deviceClassNetName, err = SetupDiClassNameFromGuidEx(&deviceClassNetGUID, computerName)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiClassNameFromGuidEx: %s", err.Error())
|
||||
} else if strings.ToLower(deviceClassNetName) != "net" {
|
||||
t.Errorf("SetupDiClassNameFromGuidEx(%x) should return \"Net\"", deviceClassNetGUID)
|
||||
}
|
||||
|
||||
_, err = SetupDiClassNameFromGuidEx(nil, "")
|
||||
if err == nil {
|
||||
t.Errorf("SetupDiClassNameFromGuidEx(nil) should fail")
|
||||
} else {
|
||||
if errWin, ok := err.(syscall.Errno); !ok || errWin != 1784 /*ERROR_INVALID_USER_BUFFER*/ {
|
||||
t.Errorf("SetupDiClassNameFromGuidEx(nil) should fail with ERROR_INVALID_USER_BUFFER")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiClassGuidsFromNameEx(t *testing.T) {
|
||||
ClassGUIDs, err := SetupDiClassGuidsFromNameEx("Net", "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiClassGuidsFromNameEx: %s", err.Error())
|
||||
} else {
|
||||
found := false
|
||||
for i := range ClassGUIDs {
|
||||
if ClassGUIDs[i] == deviceClassNetGUID {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Errorf("SetupDiClassGuidsFromNameEx(\"Net\") should return %x", deviceClassNetGUID)
|
||||
}
|
||||
}
|
||||
|
||||
ClassGUIDs, err = SetupDiClassGuidsFromNameEx("foobar-34274a51-a6e6-45f0-80d6-c62be96dd5fe", computerName)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiClassGuidsFromNameEx: %s", err.Error())
|
||||
} else if len(ClassGUIDs) != 0 {
|
||||
t.Errorf("SetupDiClassGuidsFromNameEx(\"foobar-34274a51-a6e6-45f0-80d6-c62be96dd5fe\") should return an empty GUID set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetupDiGetSelectedDevice(t *testing.T) {
|
||||
devInfoList, err := SetupDiGetClassDevsEx(&deviceClassNetGUID, "", 0, DIGCF_PRESENT, DevInfo(0), "")
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetClassDevsEx: %s", err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
for i := 0; true; i++ {
|
||||
data, err := devInfoList.EnumDeviceInfo(i)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
err = devInfoList.SetSelectedDevice(data)
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiSetSelectedDevice: %s", err.Error())
|
||||
}
|
||||
|
||||
data2, err := devInfoList.GetSelectedDevice()
|
||||
if err != nil {
|
||||
t.Errorf("Error calling SetupDiGetSelectedDevice: %s", err.Error())
|
||||
} else if *data != *data2 {
|
||||
t.Error("SetupDiGetSelectedDevice returned different data than was set by SetupDiSetSelectedDevice")
|
||||
}
|
||||
}
|
||||
|
||||
err = devInfoList.SetSelectedDevice(nil)
|
||||
if err == nil {
|
||||
t.Errorf("SetupDiSetSelectedDevice(nil) should fail")
|
||||
} else {
|
||||
if errWin, ok := err.(syscall.Errno); !ok || errWin != 87 /*ERROR_INVALID_PARAMETER*/ {
|
||||
t.Errorf("SetupDiSetSelectedDevice(nil) should fail with ERROR_INVALID_USER_BUFFER")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUTF16ToBuf(t *testing.T) {
|
||||
buf := []uint16{0x0123, 0x4567, 0x89ab, 0xcdef}
|
||||
buf2 := UTF16ToBuf(buf)
|
||||
if len(buf)*2 != len(buf2) ||
|
||||
cap(buf)*2 != cap(buf2) ||
|
||||
buf2[0] != 0x23 || buf2[1] != 0x01 ||
|
||||
buf2[2] != 0x67 || buf2[3] != 0x45 ||
|
||||
buf2[4] != 0xab || buf2[5] != 0x89 ||
|
||||
buf2[6] != 0xef || buf2[7] != 0xcd {
|
||||
t.Errorf("SetupDiSetSelectedDevice(nil) should fail with ERROR_INVALID_USER_BUFFER")
|
||||
}
|
||||
}
|
||||
539
tun/wintun/setupapi/types_windows.go
Normal file
539
tun/wintun/setupapi/types_windows.go
Normal file
@@ -0,0 +1,539 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package setupapi
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
const (
|
||||
MAX_DEVICE_ID_LEN = 200
|
||||
MAX_DEVNODE_ID_LEN = MAX_DEVICE_ID_LEN
|
||||
MAX_GUID_STRING_LEN = 39 // 38 chars + terminator null
|
||||
MAX_CLASS_NAME_LEN = 32
|
||||
MAX_PROFILE_LEN = 80
|
||||
MAX_CONFIG_VALUE = 9999
|
||||
MAX_INSTANCE_VALUE = 9999
|
||||
CONFIGMG_VERSION = 0x0400
|
||||
)
|
||||
|
||||
//
|
||||
// Define maximum string length constants
|
||||
//
|
||||
const (
|
||||
LINE_LEN = 256 // Windows 9x-compatible maximum for displayable strings coming from a device INF.
|
||||
MAX_INF_STRING_LENGTH = 4096 // Actual maximum size of an INF string (including string substitutions).
|
||||
MAX_INF_SECTION_NAME_LENGTH = 255 // For Windows 9x compatibility, INF section names should be constrained to 32 characters.
|
||||
MAX_TITLE_LEN = 60
|
||||
MAX_INSTRUCTION_LEN = 256
|
||||
MAX_LABEL_LEN = 30
|
||||
MAX_SERVICE_NAME_LEN = 256
|
||||
MAX_SUBTITLE_LEN = 256
|
||||
)
|
||||
|
||||
const (
|
||||
// SP_MAX_MACHINENAME_LENGTH defines maximum length of a machine name in the format expected by ConfigMgr32 CM_Connect_Machine (i.e., "\\\\MachineName\0").
|
||||
SP_MAX_MACHINENAME_LENGTH = windows.MAX_PATH + 3
|
||||
)
|
||||
|
||||
// HSPFILEQ is type for setup file queue
|
||||
type HSPFILEQ uintptr
|
||||
|
||||
// DevInfo holds reference to device information set
|
||||
type DevInfo windows.Handle
|
||||
|
||||
// DevInfoData is a device information structure (references a device instance that is a member of a device information set)
|
||||
type DevInfoData struct {
|
||||
size uint32
|
||||
ClassGUID windows.GUID
|
||||
DevInst uint32 // DEVINST handle
|
||||
_ uintptr
|
||||
}
|
||||
|
||||
// DevInfoListDetailData is a structure for detailed information on a device information set (used for SetupDiGetDeviceInfoListDetail which supercedes the functionality of SetupDiGetDeviceInfoListClass).
|
||||
type DevInfoListDetailData struct {
|
||||
size uint32
|
||||
ClassGUID windows.GUID
|
||||
RemoteMachineHandle windows.Handle
|
||||
remoteMachineName [SP_MAX_MACHINENAME_LENGTH]uint16
|
||||
}
|
||||
|
||||
func (data *DevInfoListDetailData) GetRemoteMachineName() string {
|
||||
return windows.UTF16ToString(data.remoteMachineName[:])
|
||||
}
|
||||
|
||||
func (data *DevInfoListDetailData) SetRemoteMachineName(remoteMachineName string) error {
|
||||
str, err := syscall.UTF16FromString(remoteMachineName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copy(data.remoteMachineName[:], str)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DI_FUNCTION is function type for device installer
|
||||
type DI_FUNCTION uint32
|
||||
|
||||
const (
|
||||
DIF_SELECTDEVICE DI_FUNCTION = 0x00000001
|
||||
DIF_INSTALLDEVICE DI_FUNCTION = 0x00000002
|
||||
DIF_ASSIGNRESOURCES DI_FUNCTION = 0x00000003
|
||||
DIF_PROPERTIES DI_FUNCTION = 0x00000004
|
||||
DIF_REMOVE DI_FUNCTION = 0x00000005
|
||||
DIF_FIRSTTIMESETUP DI_FUNCTION = 0x00000006
|
||||
DIF_FOUNDDEVICE DI_FUNCTION = 0x00000007
|
||||
DIF_SELECTCLASSDRIVERS DI_FUNCTION = 0x00000008
|
||||
DIF_VALIDATECLASSDRIVERS DI_FUNCTION = 0x00000009
|
||||
DIF_INSTALLCLASSDRIVERS DI_FUNCTION = 0x0000000A
|
||||
DIF_CALCDISKSPACE DI_FUNCTION = 0x0000000B
|
||||
DIF_DESTROYPRIVATEDATA DI_FUNCTION = 0x0000000C
|
||||
DIF_VALIDATEDRIVER DI_FUNCTION = 0x0000000D
|
||||
DIF_DETECT DI_FUNCTION = 0x0000000F
|
||||
DIF_INSTALLWIZARD DI_FUNCTION = 0x00000010
|
||||
DIF_DESTROYWIZARDDATA DI_FUNCTION = 0x00000011
|
||||
DIF_PROPERTYCHANGE DI_FUNCTION = 0x00000012
|
||||
DIF_ENABLECLASS DI_FUNCTION = 0x00000013
|
||||
DIF_DETECTVERIFY DI_FUNCTION = 0x00000014
|
||||
DIF_INSTALLDEVICEFILES DI_FUNCTION = 0x00000015
|
||||
DIF_UNREMOVE DI_FUNCTION = 0x00000016
|
||||
DIF_SELECTBESTCOMPATDRV DI_FUNCTION = 0x00000017
|
||||
DIF_ALLOW_INSTALL DI_FUNCTION = 0x00000018
|
||||
DIF_REGISTERDEVICE DI_FUNCTION = 0x00000019
|
||||
DIF_NEWDEVICEWIZARD_PRESELECT DI_FUNCTION = 0x0000001A
|
||||
DIF_NEWDEVICEWIZARD_SELECT DI_FUNCTION = 0x0000001B
|
||||
DIF_NEWDEVICEWIZARD_PREANALYZE DI_FUNCTION = 0x0000001C
|
||||
DIF_NEWDEVICEWIZARD_POSTANALYZE DI_FUNCTION = 0x0000001D
|
||||
DIF_NEWDEVICEWIZARD_FINISHINSTALL DI_FUNCTION = 0x0000001E
|
||||
DIF_INSTALLINTERFACES DI_FUNCTION = 0x00000020
|
||||
DIF_DETECTCANCEL DI_FUNCTION = 0x00000021
|
||||
DIF_REGISTER_COINSTALLERS DI_FUNCTION = 0x00000022
|
||||
DIF_ADDPROPERTYPAGE_ADVANCED DI_FUNCTION = 0x00000023
|
||||
DIF_ADDPROPERTYPAGE_BASIC DI_FUNCTION = 0x00000024
|
||||
DIF_TROUBLESHOOTER DI_FUNCTION = 0x00000026
|
||||
DIF_POWERMESSAGEWAKE DI_FUNCTION = 0x00000027
|
||||
DIF_ADDREMOTEPROPERTYPAGE_ADVANCED DI_FUNCTION = 0x00000028
|
||||
DIF_UPDATEDRIVER_UI DI_FUNCTION = 0x00000029
|
||||
DIF_FINISHINSTALL_ACTION DI_FUNCTION = 0x0000002A
|
||||
)
|
||||
|
||||
// DevInstallParams is device installation parameters structure (associated with a particular device information element, or globally with a device information set)
|
||||
type DevInstallParams struct {
|
||||
size uint32
|
||||
Flags DI_FLAGS
|
||||
FlagsEx DI_FLAGSEX
|
||||
hwndParent uintptr
|
||||
InstallMsgHandler uintptr
|
||||
InstallMsgHandlerContext uintptr
|
||||
FileQueue HSPFILEQ
|
||||
_ uintptr
|
||||
_ uint32
|
||||
driverPath [windows.MAX_PATH]uint16
|
||||
}
|
||||
|
||||
func (params *DevInstallParams) GetDriverPath() string {
|
||||
return windows.UTF16ToString(params.driverPath[:])
|
||||
}
|
||||
|
||||
func (params *DevInstallParams) SetDriverPath(driverPath string) error {
|
||||
str, err := syscall.UTF16FromString(driverPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copy(params.driverPath[:], str)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DI_FLAGS is SP_DEVINSTALL_PARAMS.Flags values
|
||||
type DI_FLAGS uint32
|
||||
|
||||
const (
|
||||
// Flags for choosing a device
|
||||
DI_SHOWOEM DI_FLAGS = 0x00000001 // support Other... button
|
||||
DI_SHOWCOMPAT DI_FLAGS = 0x00000002 // show compatibility list
|
||||
DI_SHOWCLASS DI_FLAGS = 0x00000004 // show class list
|
||||
DI_SHOWALL DI_FLAGS = 0x00000007 // both class & compat list shown
|
||||
DI_NOVCP DI_FLAGS = 0x00000008 // don't create a new copy queue--use caller-supplied FileQueue
|
||||
DI_DIDCOMPAT DI_FLAGS = 0x00000010 // Searched for compatible devices
|
||||
DI_DIDCLASS DI_FLAGS = 0x00000020 // Searched for class devices
|
||||
DI_AUTOASSIGNRES DI_FLAGS = 0x00000040 // No UI for resources if possible
|
||||
|
||||
// Flags returned by DiInstallDevice to indicate need to reboot/restart
|
||||
DI_NEEDRESTART DI_FLAGS = 0x00000080 // Reboot required to take effect
|
||||
DI_NEEDREBOOT DI_FLAGS = 0x00000100 // ""
|
||||
|
||||
// Flags for device installation
|
||||
DI_NOBROWSE DI_FLAGS = 0x00000200 // no Browse... in InsertDisk
|
||||
|
||||
// Flags set by DiBuildDriverInfoList
|
||||
DI_MULTMFGS DI_FLAGS = 0x00000400 // Set if multiple manufacturers in class driver list
|
||||
|
||||
// Flag indicates that device is disabled
|
||||
DI_DISABLED DI_FLAGS = 0x00000800 // Set if device disabled
|
||||
|
||||
// Flags for Device/Class Properties
|
||||
DI_GENERALPAGE_ADDED DI_FLAGS = 0x00001000
|
||||
DI_RESOURCEPAGE_ADDED DI_FLAGS = 0x00002000
|
||||
|
||||
// Flag to indicate the setting properties for this Device (or class) caused a change so the Dev Mgr UI probably needs to be updated.
|
||||
DI_PROPERTIES_CHANGE DI_FLAGS = 0x00004000
|
||||
|
||||
// Flag to indicate that the sorting from the INF file should be used.
|
||||
DI_INF_IS_SORTED DI_FLAGS = 0x00008000
|
||||
|
||||
// Flag to indicate that only the the INF specified by SP_DEVINSTALL_PARAMS.DriverPath should be searched.
|
||||
DI_ENUMSINGLEINF DI_FLAGS = 0x00010000
|
||||
|
||||
// Flag that prevents ConfigMgr from removing/re-enumerating devices during device
|
||||
// registration, installation, and deletion.
|
||||
DI_DONOTCALLCONFIGMG DI_FLAGS = 0x00020000
|
||||
|
||||
// The following flag can be used to install a device disabled
|
||||
DI_INSTALLDISABLED DI_FLAGS = 0x00040000
|
||||
|
||||
// Flag that causes SetupDiBuildDriverInfoList to build a device's compatible driver
|
||||
// list from its existing class driver list, instead of the normal INF search.
|
||||
DI_COMPAT_FROM_CLASS DI_FLAGS = 0x00080000
|
||||
|
||||
// This flag is set if the Class Install params should be used.
|
||||
DI_CLASSINSTALLPARAMS DI_FLAGS = 0x00100000
|
||||
|
||||
// This flag is set if the caller of DiCallClassInstaller does NOT want the internal default action performed if the Class installer returns ERROR_DI_DO_DEFAULT.
|
||||
DI_NODI_DEFAULTACTION DI_FLAGS = 0x00200000
|
||||
|
||||
// Flags for device installation
|
||||
DI_QUIETINSTALL DI_FLAGS = 0x00800000 // don't confuse the user with questions or excess info
|
||||
DI_NOFILECOPY DI_FLAGS = 0x01000000 // No file Copy necessary
|
||||
DI_FORCECOPY DI_FLAGS = 0x02000000 // Force files to be copied from install path
|
||||
DI_DRIVERPAGE_ADDED DI_FLAGS = 0x04000000 // Prop provider added Driver page.
|
||||
DI_USECI_SELECTSTRINGS DI_FLAGS = 0x08000000 // Use Class Installer Provided strings in the Select Device Dlg
|
||||
DI_OVERRIDE_INFFLAGS DI_FLAGS = 0x10000000 // Override INF flags
|
||||
DI_PROPS_NOCHANGEUSAGE DI_FLAGS = 0x20000000 // No Enable/Disable in General Props
|
||||
|
||||
DI_NOSELECTICONS DI_FLAGS = 0x40000000 // No small icons in select device dialogs
|
||||
|
||||
DI_NOWRITE_IDS DI_FLAGS = 0x80000000 // Don't write HW & Compat IDs on install
|
||||
)
|
||||
|
||||
// DI_FLAGSEX is SP_DEVINSTALL_PARAMS.FlagsEx values
|
||||
type DI_FLAGSEX uint32
|
||||
|
||||
const (
|
||||
DI_FLAGSEX_CI_FAILED DI_FLAGSEX = 0x00000004 // Failed to Load/Call class installer
|
||||
DI_FLAGSEX_FINISHINSTALL_ACTION DI_FLAGSEX = 0x00000008 // Class/co-installer wants to get a DIF_FINISH_INSTALL action in client context.
|
||||
DI_FLAGSEX_DIDINFOLIST DI_FLAGSEX = 0x00000010 // Did the Class Info List
|
||||
DI_FLAGSEX_DIDCOMPATINFO DI_FLAGSEX = 0x00000020 // Did the Compat Info List
|
||||
DI_FLAGSEX_FILTERCLASSES DI_FLAGSEX = 0x00000040
|
||||
DI_FLAGSEX_SETFAILEDINSTALL DI_FLAGSEX = 0x00000080
|
||||
DI_FLAGSEX_DEVICECHANGE DI_FLAGSEX = 0x00000100
|
||||
DI_FLAGSEX_ALWAYSWRITEIDS DI_FLAGSEX = 0x00000200
|
||||
DI_FLAGSEX_PROPCHANGE_PENDING DI_FLAGSEX = 0x00000400 // One or more device property sheets have had changes made to them, and need to have a DIF_PROPERTYCHANGE occur.
|
||||
DI_FLAGSEX_ALLOWEXCLUDEDDRVS DI_FLAGSEX = 0x00000800
|
||||
DI_FLAGSEX_NOUIONQUERYREMOVE DI_FLAGSEX = 0x00001000
|
||||
DI_FLAGSEX_USECLASSFORCOMPAT DI_FLAGSEX = 0x00002000 // Use the device's class when building compat drv list. (Ignored if DI_COMPAT_FROM_CLASS flag is specified.)
|
||||
DI_FLAGSEX_NO_DRVREG_MODIFY DI_FLAGSEX = 0x00008000 // Don't run AddReg and DelReg for device's software (driver) key.
|
||||
DI_FLAGSEX_IN_SYSTEM_SETUP DI_FLAGSEX = 0x00010000 // Installation is occurring during initial system setup.
|
||||
DI_FLAGSEX_INET_DRIVER DI_FLAGSEX = 0x00020000 // Driver came from Windows Update
|
||||
DI_FLAGSEX_APPENDDRIVERLIST DI_FLAGSEX = 0x00040000 // Cause SetupDiBuildDriverInfoList to append a new driver list to an existing list.
|
||||
DI_FLAGSEX_PREINSTALLBACKUP DI_FLAGSEX = 0x00080000 // not used
|
||||
DI_FLAGSEX_BACKUPONREPLACE DI_FLAGSEX = 0x00100000 // not used
|
||||
DI_FLAGSEX_DRIVERLIST_FROM_URL DI_FLAGSEX = 0x00200000 // build driver list from INF(s) retrieved from URL specified in SP_DEVINSTALL_PARAMS.DriverPath (empty string means Windows Update website)
|
||||
DI_FLAGSEX_EXCLUDE_OLD_INET_DRIVERS DI_FLAGSEX = 0x00800000 // Don't include old Internet drivers when building a driver list. Ignored on Windows Vista and later.
|
||||
DI_FLAGSEX_POWERPAGE_ADDED DI_FLAGSEX = 0x01000000 // class installer added their own power page
|
||||
DI_FLAGSEX_FILTERSIMILARDRIVERS DI_FLAGSEX = 0x02000000 // only include similar drivers in class list
|
||||
DI_FLAGSEX_INSTALLEDDRIVER DI_FLAGSEX = 0x04000000 // only add the installed driver to the class or compat driver list. Used in calls to SetupDiBuildDriverInfoList
|
||||
DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE DI_FLAGSEX = 0x08000000 // Don't remove identical driver nodes from the class list
|
||||
DI_FLAGSEX_ALTPLATFORM_DRVSEARCH DI_FLAGSEX = 0x10000000 // Build driver list based on alternate platform information specified in associated file queue
|
||||
DI_FLAGSEX_RESTART_DEVICE_ONLY DI_FLAGSEX = 0x20000000 // only restart the device drivers are being installed on as opposed to restarting all devices using those drivers.
|
||||
DI_FLAGSEX_RECURSIVESEARCH DI_FLAGSEX = 0x40000000 // Tell SetupDiBuildDriverInfoList to do a recursive search
|
||||
DI_FLAGSEX_SEARCH_PUBLISHED_INFS DI_FLAGSEX = 0x80000000 // Tell SetupDiBuildDriverInfoList to do a "published INF" search
|
||||
)
|
||||
|
||||
// ClassInstallHeader is the first member of any class install parameters structure. It contains the device installation request code that defines the format of the rest of the install parameters structure.
|
||||
type ClassInstallHeader struct {
|
||||
size uint32
|
||||
InstallFunction DI_FUNCTION
|
||||
}
|
||||
|
||||
func MakeClassInstallHeader(installFunction DI_FUNCTION) *ClassInstallHeader {
|
||||
hdr := &ClassInstallHeader{InstallFunction: installFunction}
|
||||
hdr.size = uint32(unsafe.Sizeof(*hdr))
|
||||
return hdr
|
||||
}
|
||||
|
||||
// DICS_FLAG specifies the scope of a device property change
|
||||
type DICS_FLAG uint32
|
||||
|
||||
const (
|
||||
DICS_FLAG_GLOBAL DICS_FLAG = 0x00000001 // make change in all hardware profiles
|
||||
DICS_FLAG_CONFIGSPECIFIC DICS_FLAG = 0x00000002 // make change in specified profile only
|
||||
DICS_FLAG_CONFIGGENERAL DICS_FLAG = 0x00000004 // 1 or more hardware profile-specific changes to follow
|
||||
)
|
||||
|
||||
// DI_REMOVEDEVICE specifies the scope of the device removal
|
||||
type DI_REMOVEDEVICE uint32
|
||||
|
||||
const (
|
||||
DI_REMOVEDEVICE_GLOBAL DI_REMOVEDEVICE = 0x00000001 // Make this change in all hardware profiles. Remove information about the device from the registry.
|
||||
DI_REMOVEDEVICE_CONFIGSPECIFIC DI_REMOVEDEVICE = 0x00000002 // Make this change to only the hardware profile specified by HwProfile. this flag only applies to root-enumerated devices. When Windows removes the device from the last hardware profile in which it was configured, Windows performs a global removal.
|
||||
)
|
||||
|
||||
// RemoveDeviceParams is a structure corresponding to a DIF_REMOVE install function.
|
||||
type RemoveDeviceParams struct {
|
||||
ClassInstallHeader ClassInstallHeader
|
||||
Scope DI_REMOVEDEVICE
|
||||
HwProfile uint32
|
||||
}
|
||||
|
||||
// DrvInfoData is driver information structure (member of a driver info list that may be associated with a particular device instance, or (globally) with a device information set)
|
||||
type DrvInfoData struct {
|
||||
size uint32
|
||||
DriverType uint32
|
||||
_ uintptr
|
||||
description [LINE_LEN]uint16
|
||||
mfgName [LINE_LEN]uint16
|
||||
providerName [LINE_LEN]uint16
|
||||
DriverDate windows.Filetime
|
||||
DriverVersion uint64
|
||||
}
|
||||
|
||||
func (data *DrvInfoData) GetDescription() string {
|
||||
return windows.UTF16ToString(data.description[:])
|
||||
}
|
||||
|
||||
func (data *DrvInfoData) SetDescription(description string) error {
|
||||
str, err := syscall.UTF16FromString(description)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copy(data.description[:], str)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (data *DrvInfoData) GetMfgName() string {
|
||||
return windows.UTF16ToString(data.mfgName[:])
|
||||
}
|
||||
|
||||
func (data *DrvInfoData) SetMfgName(mfgName string) error {
|
||||
str, err := syscall.UTF16FromString(mfgName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copy(data.mfgName[:], str)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (data *DrvInfoData) GetProviderName() string {
|
||||
return windows.UTF16ToString(data.providerName[:])
|
||||
}
|
||||
|
||||
func (data *DrvInfoData) SetProviderName(providerName string) error {
|
||||
str, err := syscall.UTF16FromString(providerName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copy(data.providerName[:], str)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsNewer method returns true if DrvInfoData date and version is newer than supplied parameters.
|
||||
func (data *DrvInfoData) IsNewer(driverDate windows.Filetime, driverVersion uint64) bool {
|
||||
if data.DriverDate.HighDateTime > driverDate.HighDateTime {
|
||||
return true
|
||||
}
|
||||
if data.DriverDate.HighDateTime < driverDate.HighDateTime {
|
||||
return false
|
||||
}
|
||||
|
||||
if data.DriverDate.LowDateTime > driverDate.LowDateTime {
|
||||
return true
|
||||
}
|
||||
if data.DriverDate.LowDateTime < driverDate.LowDateTime {
|
||||
return false
|
||||
}
|
||||
|
||||
if data.DriverVersion > driverVersion {
|
||||
return true
|
||||
}
|
||||
if data.DriverVersion < driverVersion {
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// DrvInfoDetailData is driver information details structure (provides detailed information about a particular driver information structure)
|
||||
type DrvInfoDetailData struct {
|
||||
size uint32 // On input, this must be exactly the sizeof(DrvInfoDetailData). On output, we set this member to the actual size of structure data.
|
||||
InfDate windows.Filetime
|
||||
compatIDsOffset uint32
|
||||
compatIDsLength uint32
|
||||
_ uintptr
|
||||
sectionName [LINE_LEN]uint16
|
||||
infFileName [windows.MAX_PATH]uint16
|
||||
drvDescription [LINE_LEN]uint16
|
||||
hardwareID [1]uint16
|
||||
}
|
||||
|
||||
func (data *DrvInfoDetailData) GetSectionName() string {
|
||||
return windows.UTF16ToString(data.sectionName[:])
|
||||
}
|
||||
|
||||
func (data *DrvInfoDetailData) GetInfFileName() string {
|
||||
return windows.UTF16ToString(data.infFileName[:])
|
||||
}
|
||||
|
||||
func (data *DrvInfoDetailData) GetDrvDescription() string {
|
||||
return windows.UTF16ToString(data.drvDescription[:])
|
||||
}
|
||||
|
||||
func (data *DrvInfoDetailData) GetHardwareID() string {
|
||||
if data.compatIDsOffset > 1 {
|
||||
bufW := data.getBuf()
|
||||
return windows.UTF16ToString(bufW[:wcslen(bufW)])
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (data *DrvInfoDetailData) GetCompatIDs() []string {
|
||||
a := make([]string, 0)
|
||||
|
||||
if data.compatIDsLength > 0 {
|
||||
bufW := data.getBuf()
|
||||
bufW = bufW[data.compatIDsOffset : data.compatIDsOffset+data.compatIDsLength]
|
||||
for i := 0; i < len(bufW); {
|
||||
j := i + wcslen(bufW[i:])
|
||||
if i < j {
|
||||
a = append(a, windows.UTF16ToString(bufW[i:j]))
|
||||
}
|
||||
i = j + 1
|
||||
}
|
||||
}
|
||||
|
||||
return a
|
||||
}
|
||||
|
||||
func (data *DrvInfoDetailData) getBuf() []uint16 {
|
||||
len := (data.size - uint32(unsafe.Offsetof(data.hardwareID))) / 2
|
||||
sl := struct {
|
||||
addr *uint16
|
||||
len int
|
||||
cap int
|
||||
}{&data.hardwareID[0], int(len), int(len)}
|
||||
return *(*[]uint16)(unsafe.Pointer(&sl))
|
||||
}
|
||||
|
||||
// IsCompatible method tests if given hardware ID matches the driver or is listed on the compatible ID list.
|
||||
func (data *DrvInfoDetailData) IsCompatible(hwid string) bool {
|
||||
hwidLC := strings.ToLower(hwid)
|
||||
if strings.ToLower(data.GetHardwareID()) == hwidLC {
|
||||
return true
|
||||
}
|
||||
a := data.GetCompatIDs()
|
||||
for i := range a {
|
||||
if strings.ToLower(a[i]) == hwidLC {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// DICD flags control SetupDiCreateDeviceInfo
|
||||
type DICD uint32
|
||||
|
||||
const (
|
||||
DICD_GENERATE_ID DICD = 0x00000001
|
||||
DICD_INHERIT_CLASSDRVS DICD = 0x00000002
|
||||
)
|
||||
|
||||
//
|
||||
// SPDIT flags to distinguish between class drivers and
|
||||
// device drivers.
|
||||
// (Passed in 'DriverType' parameter of driver information list APIs)
|
||||
//
|
||||
type SPDIT uint32
|
||||
|
||||
const (
|
||||
SPDIT_NODRIVER SPDIT = 0x00000000
|
||||
SPDIT_CLASSDRIVER SPDIT = 0x00000001
|
||||
SPDIT_COMPATDRIVER SPDIT = 0x00000002
|
||||
)
|
||||
|
||||
// DIGCF flags control what is included in the device information set built by SetupDiGetClassDevs
|
||||
type DIGCF uint32
|
||||
|
||||
const (
|
||||
DIGCF_DEFAULT DIGCF = 0x00000001 // only valid with DIGCF_DEVICEINTERFACE
|
||||
DIGCF_PRESENT DIGCF = 0x00000002
|
||||
DIGCF_ALLCLASSES DIGCF = 0x00000004
|
||||
DIGCF_PROFILE DIGCF = 0x00000008
|
||||
DIGCF_DEVICEINTERFACE DIGCF = 0x00000010
|
||||
)
|
||||
|
||||
// DIREG specifies values for SetupDiCreateDevRegKey, SetupDiOpenDevRegKey, and SetupDiDeleteDevRegKey.
|
||||
type DIREG uint32
|
||||
|
||||
const (
|
||||
DIREG_DEV DIREG = 0x00000001 // Open/Create/Delete device key
|
||||
DIREG_DRV DIREG = 0x00000002 // Open/Create/Delete driver key
|
||||
DIREG_BOTH DIREG = 0x00000004 // Delete both driver and Device key
|
||||
)
|
||||
|
||||
//
|
||||
// SPDRP specifies device registry property codes
|
||||
// (Codes marked as read-only (R) may only be used for
|
||||
// SetupDiGetDeviceRegistryProperty)
|
||||
//
|
||||
// These values should cover the same set of registry properties
|
||||
// as defined by the CM_DRP codes in cfgmgr32.h.
|
||||
//
|
||||
// Note that SPDRP codes are zero based while CM_DRP codes are one based!
|
||||
//
|
||||
type SPDRP uint32
|
||||
|
||||
const (
|
||||
SPDRP_DEVICEDESC SPDRP = 0x00000000 // DeviceDesc (R/W)
|
||||
SPDRP_HARDWAREID SPDRP = 0x00000001 // HardwareID (R/W)
|
||||
SPDRP_COMPATIBLEIDS SPDRP = 0x00000002 // CompatibleIDs (R/W)
|
||||
SPDRP_SERVICE SPDRP = 0x00000004 // Service (R/W)
|
||||
SPDRP_CLASS SPDRP = 0x00000007 // Class (R--tied to ClassGUID)
|
||||
SPDRP_CLASSGUID SPDRP = 0x00000008 // ClassGUID (R/W)
|
||||
SPDRP_DRIVER SPDRP = 0x00000009 // Driver (R/W)
|
||||
SPDRP_CONFIGFLAGS SPDRP = 0x0000000A // ConfigFlags (R/W)
|
||||
SPDRP_MFG SPDRP = 0x0000000B // Mfg (R/W)
|
||||
SPDRP_FRIENDLYNAME SPDRP = 0x0000000C // FriendlyName (R/W)
|
||||
SPDRP_LOCATION_INFORMATION SPDRP = 0x0000000D // LocationInformation (R/W)
|
||||
SPDRP_PHYSICAL_DEVICE_OBJECT_NAME SPDRP = 0x0000000E // PhysicalDeviceObjectName (R)
|
||||
SPDRP_CAPABILITIES SPDRP = 0x0000000F // Capabilities (R)
|
||||
SPDRP_UI_NUMBER SPDRP = 0x00000010 // UiNumber (R)
|
||||
SPDRP_UPPERFILTERS SPDRP = 0x00000011 // UpperFilters (R/W)
|
||||
SPDRP_LOWERFILTERS SPDRP = 0x00000012 // LowerFilters (R/W)
|
||||
SPDRP_BUSTYPEGUID SPDRP = 0x00000013 // BusTypeGUID (R)
|
||||
SPDRP_LEGACYBUSTYPE SPDRP = 0x00000014 // LegacyBusType (R)
|
||||
SPDRP_BUSNUMBER SPDRP = 0x00000015 // BusNumber (R)
|
||||
SPDRP_ENUMERATOR_NAME SPDRP = 0x00000016 // Enumerator Name (R)
|
||||
SPDRP_SECURITY SPDRP = 0x00000017 // Security (R/W, binary form)
|
||||
SPDRP_SECURITY_SDS SPDRP = 0x00000018 // Security (W, SDS form)
|
||||
SPDRP_DEVTYPE SPDRP = 0x00000019 // Device Type (R/W)
|
||||
SPDRP_EXCLUSIVE SPDRP = 0x0000001A // Device is exclusive-access (R/W)
|
||||
SPDRP_CHARACTERISTICS SPDRP = 0x0000001B // Device Characteristics (R/W)
|
||||
SPDRP_ADDRESS SPDRP = 0x0000001C // Device Address (R)
|
||||
SPDRP_UI_NUMBER_DESC_FORMAT SPDRP = 0x0000001D // UiNumberDescFormat (R/W)
|
||||
SPDRP_DEVICE_POWER_DATA SPDRP = 0x0000001E // Device Power Data (R)
|
||||
SPDRP_REMOVAL_POLICY SPDRP = 0x0000001F // Removal Policy (R)
|
||||
SPDRP_REMOVAL_POLICY_HW_DEFAULT SPDRP = 0x00000020 // Hardware Removal Policy (R)
|
||||
SPDRP_REMOVAL_POLICY_OVERRIDE SPDRP = 0x00000021 // Removal Policy Override (RW)
|
||||
SPDRP_INSTALL_STATE SPDRP = 0x00000022 // Device Install State (R)
|
||||
SPDRP_LOCATION_PATHS SPDRP = 0x00000023 // Device Location Paths (R)
|
||||
SPDRP_BASE_CONTAINERID SPDRP = 0x00000024 // Base ContainerID (R)
|
||||
|
||||
SPDRP_MAXIMUM_PROPERTY SPDRP = 0x00000025 // Upper bound on ordinals
|
||||
)
|
||||
370
tun/wintun/setupapi/zsetupapi_windows.go
Normal file
370
tun/wintun/setupapi/zsetupapi_windows.go
Normal file
@@ -0,0 +1,370 @@
|
||||
// Code generated by 'go generate'; DO NOT EDIT.
|
||||
|
||||
package setupapi
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
// Do the interface allocations only once for common
|
||||
// Errno values.
|
||||
const (
|
||||
errnoERROR_IO_PENDING = 997
|
||||
)
|
||||
|
||||
var (
|
||||
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
|
||||
)
|
||||
|
||||
// errnoErr returns common boxed Errno values, to prevent
|
||||
// allocations at runtime.
|
||||
func errnoErr(e syscall.Errno) error {
|
||||
switch e {
|
||||
case 0:
|
||||
return nil
|
||||
case errnoERROR_IO_PENDING:
|
||||
return errERROR_IO_PENDING
|
||||
}
|
||||
// TODO: add more here, after collecting data on the common
|
||||
// error values see on Windows. (perhaps when running
|
||||
// all.bat?)
|
||||
return e
|
||||
}
|
||||
|
||||
var (
|
||||
modsetupapi = windows.NewLazySystemDLL("setupapi.dll")
|
||||
|
||||
procSetupDiCreateDeviceInfoListExW = modsetupapi.NewProc("SetupDiCreateDeviceInfoListExW")
|
||||
procSetupDiGetDeviceInfoListDetailW = modsetupapi.NewProc("SetupDiGetDeviceInfoListDetailW")
|
||||
procSetupDiCreateDeviceInfoW = modsetupapi.NewProc("SetupDiCreateDeviceInfoW")
|
||||
procSetupDiEnumDeviceInfo = modsetupapi.NewProc("SetupDiEnumDeviceInfo")
|
||||
procSetupDiDestroyDeviceInfoList = modsetupapi.NewProc("SetupDiDestroyDeviceInfoList")
|
||||
procSetupDiBuildDriverInfoList = modsetupapi.NewProc("SetupDiBuildDriverInfoList")
|
||||
procSetupDiCancelDriverInfoSearch = modsetupapi.NewProc("SetupDiCancelDriverInfoSearch")
|
||||
procSetupDiEnumDriverInfoW = modsetupapi.NewProc("SetupDiEnumDriverInfoW")
|
||||
procSetupDiGetSelectedDriverW = modsetupapi.NewProc("SetupDiGetSelectedDriverW")
|
||||
procSetupDiSetSelectedDriverW = modsetupapi.NewProc("SetupDiSetSelectedDriverW")
|
||||
procSetupDiGetDriverInfoDetailW = modsetupapi.NewProc("SetupDiGetDriverInfoDetailW")
|
||||
procSetupDiDestroyDriverInfoList = modsetupapi.NewProc("SetupDiDestroyDriverInfoList")
|
||||
procSetupDiGetClassDevsExW = modsetupapi.NewProc("SetupDiGetClassDevsExW")
|
||||
procSetupDiCallClassInstaller = modsetupapi.NewProc("SetupDiCallClassInstaller")
|
||||
procSetupDiOpenDevRegKey = modsetupapi.NewProc("SetupDiOpenDevRegKey")
|
||||
procSetupDiGetDeviceRegistryPropertyW = modsetupapi.NewProc("SetupDiGetDeviceRegistryPropertyW")
|
||||
procSetupDiSetDeviceRegistryPropertyW = modsetupapi.NewProc("SetupDiSetDeviceRegistryPropertyW")
|
||||
procSetupDiGetDeviceInstallParamsW = modsetupapi.NewProc("SetupDiGetDeviceInstallParamsW")
|
||||
procSetupDiGetClassInstallParamsW = modsetupapi.NewProc("SetupDiGetClassInstallParamsW")
|
||||
procSetupDiSetDeviceInstallParamsW = modsetupapi.NewProc("SetupDiSetDeviceInstallParamsW")
|
||||
procSetupDiSetClassInstallParamsW = modsetupapi.NewProc("SetupDiSetClassInstallParamsW")
|
||||
procSetupDiClassNameFromGuidExW = modsetupapi.NewProc("SetupDiClassNameFromGuidExW")
|
||||
procSetupDiClassGuidsFromNameExW = modsetupapi.NewProc("SetupDiClassGuidsFromNameExW")
|
||||
procSetupDiGetSelectedDevice = modsetupapi.NewProc("SetupDiGetSelectedDevice")
|
||||
procSetupDiSetSelectedDevice = modsetupapi.NewProc("SetupDiSetSelectedDevice")
|
||||
)
|
||||
|
||||
func setupDiCreateDeviceInfoListEx(classGUID *windows.GUID, hwndParent uintptr, machineName *uint16, reserved uintptr) (handle DevInfo, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procSetupDiCreateDeviceInfoListExW.Addr(), 4, uintptr(unsafe.Pointer(classGUID)), uintptr(hwndParent), uintptr(unsafe.Pointer(machineName)), uintptr(reserved), 0, 0)
|
||||
handle = DevInfo(r0)
|
||||
if handle == DevInfo(windows.InvalidHandle) {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiGetDeviceInfoListDetail(deviceInfoSet DevInfo, deviceInfoSetDetailData *DevInfoListDetailData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiGetDeviceInfoListDetailW.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoSetDetailData)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiCreateDeviceInfo(deviceInfoSet DevInfo, DeviceName *uint16, classGUID *windows.GUID, DeviceDescription *uint16, hwndParent uintptr, CreationFlags DICD, deviceInfoData *DevInfoData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procSetupDiCreateDeviceInfoW.Addr(), 7, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(DeviceName)), uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(DeviceDescription)), uintptr(hwndParent), uintptr(CreationFlags), uintptr(unsafe.Pointer(deviceInfoData)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiEnumDeviceInfo(deviceInfoSet DevInfo, memberIndex uint32, deviceInfoData *DevInfoData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiEnumDeviceInfo.Addr(), 3, uintptr(deviceInfoSet), uintptr(memberIndex), uintptr(unsafe.Pointer(deviceInfoData)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiDestroyDeviceInfoList(deviceInfoSet DevInfo) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiDestroyDeviceInfoList.Addr(), 1, uintptr(deviceInfoSet), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiBuildDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiBuildDriverInfoList.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiCancelDriverInfoSearch(deviceInfoSet DevInfo) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiCancelDriverInfoSearch.Addr(), 1, uintptr(deviceInfoSet), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiEnumDriverInfo(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT, memberIndex uint32, driverInfoData *DrvInfoData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procSetupDiEnumDriverInfoW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType), uintptr(memberIndex), uintptr(unsafe.Pointer(driverInfoData)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiGetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDriverW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiSetSelectedDriver(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDriverW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiGetDriverInfoDetail(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverInfoData *DrvInfoData, driverInfoDetailData *DrvInfoDetailData, driverInfoDetailDataSize uint32, requiredSize *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procSetupDiGetDriverInfoDetailW.Addr(), 6, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(driverInfoData)), uintptr(unsafe.Pointer(driverInfoDetailData)), uintptr(driverInfoDetailDataSize), uintptr(unsafe.Pointer(requiredSize)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiDestroyDriverInfoList(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, driverType SPDIT) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiDestroyDriverInfoList.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(driverType))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiGetClassDevsEx(classGUID *windows.GUID, Enumerator *uint16, hwndParent uintptr, Flags DIGCF, deviceInfoSet DevInfo, machineName *uint16, reserved uintptr) (handle DevInfo, err error) {
|
||||
r0, _, e1 := syscall.Syscall9(procSetupDiGetClassDevsExW.Addr(), 7, uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(Enumerator)), uintptr(hwndParent), uintptr(Flags), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(machineName)), uintptr(reserved), 0, 0)
|
||||
handle = DevInfo(r0)
|
||||
if handle == DevInfo(windows.InvalidHandle) {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiCallClassInstaller(installFunction DI_FUNCTION, deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiCallClassInstaller.Addr(), 3, uintptr(installFunction), uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiOpenDevRegKey(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, Scope DICS_FLAG, HwProfile uint32, KeyType DIREG, samDesired uint32) (key windows.Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procSetupDiOpenDevRegKey.Addr(), 6, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(Scope), uintptr(HwProfile), uintptr(KeyType), uintptr(samDesired))
|
||||
key = windows.Handle(r0)
|
||||
if key == windows.InvalidHandle {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiGetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyRegDataType *uint32, propertyBuffer *byte, propertyBufferSize uint32, requiredSize *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procSetupDiGetDeviceRegistryPropertyW.Addr(), 7, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyRegDataType)), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), uintptr(unsafe.Pointer(requiredSize)), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiSetDeviceRegistryProperty(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, property SPDRP, propertyBuffer *byte, propertyBufferSize uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procSetupDiSetDeviceRegistryPropertyW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(property), uintptr(unsafe.Pointer(propertyBuffer)), uintptr(propertyBufferSize), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiGetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiGetDeviceInstallParamsW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiGetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32, requiredSize *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procSetupDiGetClassInstallParamsW.Addr(), 5, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), uintptr(unsafe.Pointer(requiredSize)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiSetDeviceInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, deviceInstallParams *DevInstallParams) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiSetDeviceInstallParamsW.Addr(), 3, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(deviceInstallParams)))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiSetClassInstallParams(deviceInfoSet DevInfo, deviceInfoData *DevInfoData, classInstallParams *ClassInstallHeader, classInstallParamsSize uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procSetupDiSetClassInstallParamsW.Addr(), 4, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), uintptr(unsafe.Pointer(classInstallParams)), uintptr(classInstallParamsSize), 0, 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiClassNameFromGuidEx(classGUID *windows.GUID, className *uint16, classNameSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procSetupDiClassNameFromGuidExW.Addr(), 6, uintptr(unsafe.Pointer(classGUID)), uintptr(unsafe.Pointer(className)), uintptr(classNameSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiClassGuidsFromNameEx(className *uint16, classGuidList *windows.GUID, classGuidListSize uint32, requiredSize *uint32, machineName *uint16, reserved uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procSetupDiClassGuidsFromNameExW.Addr(), 6, uintptr(unsafe.Pointer(className)), uintptr(unsafe.Pointer(classGuidList)), uintptr(classGuidListSize), uintptr(unsafe.Pointer(requiredSize)), uintptr(unsafe.Pointer(machineName)), uintptr(reserved))
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setupDiGetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiGetSelectedDevice.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetupDiSetSelectedDevice(deviceInfoSet DevInfo, deviceInfoData *DevInfoData) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupDiSetSelectedDevice.Addr(), 2, uintptr(deviceInfoSet), uintptr(unsafe.Pointer(deviceInfoData)), 0)
|
||||
if r1 == 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
20
tun/wintun/setupapi/zsetupapi_windows_test.go
Normal file
20
tun/wintun/setupapi/zsetupapi_windows_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package setupapi
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func TestSetupDiDestroyDeviceInfoList(t *testing.T) {
|
||||
err := SetupDiDestroyDeviceInfoList(DevInfo(windows.InvalidHandle))
|
||||
if errWin, ok := err.(syscall.Errno); !ok || errWin != 6 /*ERROR_INVALID_HANDLE*/ {
|
||||
t.Errorf("SetupDiDestroyDeviceInfoList(nil, ...) should fail with ERROR_INVALID_HANDLE")
|
||||
}
|
||||
}
|
||||
510
tun/wintun/wintun_windows.go
Normal file
510
tun/wintun/wintun_windows.go
Normal file
@@ -0,0 +1,510 @@
|
||||
/* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Copyright (C) 2019 WireGuard LLC. All Rights Reserved.
|
||||
*/
|
||||
|
||||
package wintun
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.zx2c4.com/wireguard/tun/wintun/netshell"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
"golang.org/x/sys/windows/registry"
|
||||
"golang.zx2c4.com/wireguard/tun/wintun/guid"
|
||||
"golang.zx2c4.com/wireguard/tun/wintun/setupapi"
|
||||
)
|
||||
|
||||
//
|
||||
// Wintun is a handle of a Wintun adapter
|
||||
//
|
||||
type Wintun struct {
|
||||
CfgInstanceID windows.GUID
|
||||
LUIDIndex uint32
|
||||
IfType uint32
|
||||
}
|
||||
|
||||
var deviceClassNetGUID = windows.GUID{Data1: 0x4d36e972, Data2: 0xe325, Data3: 0x11ce, Data4: [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}
|
||||
|
||||
const hardwareID = "Wintun"
|
||||
const enumerator = ""
|
||||
const machineName = ""
|
||||
|
||||
//
|
||||
// MakeWintun creates interface handle and populates it from device registry key
|
||||
//
|
||||
func MakeWintun(deviceInfoSet setupapi.DevInfo, deviceInfoData *setupapi.DevInfoData) (*Wintun, error) {
|
||||
// Open HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\<class>\<id> registry key.
|
||||
key, err := deviceInfoSet.OpenDevRegKey(deviceInfoData, setupapi.DICS_FLAG_GLOBAL, 0, setupapi.DIREG_DRV, registry.READ)
|
||||
if err != nil {
|
||||
return nil, errors.New("Device-specific registry key open failed: " + err.Error())
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
var valueStr string
|
||||
var valueType uint32
|
||||
|
||||
// Read the NetCfgInstanceId value.
|
||||
valueStr, valueType, err = keyGetStringValueRetry(key, "NetCfgInstanceId")
|
||||
if err != nil {
|
||||
return nil, errors.New("RegQueryStringValue(\"NetCfgInstanceId\") failed: " + err.Error())
|
||||
}
|
||||
if valueType != registry.SZ {
|
||||
return nil, fmt.Errorf("NetCfgInstanceId registry value is not REG_SZ (expected: %v, provided: %v)", registry.SZ, valueType)
|
||||
}
|
||||
|
||||
// Convert to windows.GUID.
|
||||
ifid, err := guid.FromString(valueStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("NetCfgInstanceId registry value is not a GUID (expected: \"{...}\", provided: %q)", valueStr)
|
||||
}
|
||||
|
||||
// Read the NetLuidIndex value.
|
||||
luidIdx, valueType, err := key.GetIntegerValue("NetLuidIndex")
|
||||
if err != nil {
|
||||
return nil, errors.New("RegQueryValue(\"NetLuidIndex\") failed: " + err.Error())
|
||||
}
|
||||
|
||||
// Read the NetLuidIndex value.
|
||||
ifType, valueType, err := key.GetIntegerValue("*IfType")
|
||||
if err != nil {
|
||||
return nil, errors.New("RegQueryValue(\"*IfType\") failed: " + err.Error())
|
||||
}
|
||||
|
||||
return &Wintun{
|
||||
CfgInstanceID: *ifid,
|
||||
LUIDIndex: uint32(luidIdx),
|
||||
IfType: uint32(ifType),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//
|
||||
// GetInterface finds interface by name.
|
||||
//
|
||||
// hwndParent is a handle to the top-level window to use for any user
|
||||
// interface that is related to non-device-specific actions (such as a select-
|
||||
// device dialog box that uses the global class driver list). This handle is
|
||||
// optional and can be 0. If a specific top-level window is not required, set
|
||||
// hwndParent to 0.
|
||||
//
|
||||
// Function returns interface if found, or nil otherwise. If the interface is
|
||||
// found but not Wintun-class, the function returns interface and an error.
|
||||
//
|
||||
func GetInterface(ifname string, hwndParent uintptr) (*Wintun, error) {
|
||||
// Create a list of network devices.
|
||||
devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, enumerator, hwndParent, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), machineName)
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("SetupDiGetClassDevsEx(%v) failed: ", guid.ToString(&deviceClassNetGUID)) + err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
// Windows requires each interface to have a different name. When
|
||||
// enforcing this, Windows treats interface names case-insensitive. If an
|
||||
// interface "FooBar" exists and this function reports there is no
|
||||
// interface "foobar", an attempt to create a new interface and name it
|
||||
// "foobar" would cause conflict with "FooBar".
|
||||
ifname = strings.ToLower(ifname)
|
||||
|
||||
for index := 0; ; index++ {
|
||||
// Get the device from the list. Should anything be wrong with this device, continue with next.
|
||||
deviceData, err := devInfoList.EnumDeviceInfo(index)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Get interface ID.
|
||||
wintun, err := MakeWintun(devInfoList, deviceData)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get interface name.
|
||||
ifname2, err := wintun.GetInterfaceName()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if ifname == strings.ToLower(ifname2) {
|
||||
// Interface name found. Check its driver.
|
||||
const driverType = setupapi.SPDIT_COMPATDRIVER
|
||||
err = devInfoList.BuildDriverInfoList(deviceData, driverType)
|
||||
if err != nil {
|
||||
return nil, errors.New("SetupDiBuildDriverInfoList failed: " + err.Error())
|
||||
}
|
||||
defer devInfoList.DestroyDriverInfoList(deviceData, driverType)
|
||||
|
||||
for index := 0; ; index++ {
|
||||
// Get a driver from the list.
|
||||
driverData, err := devInfoList.EnumDriverInfo(deviceData, driverType, index)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
// Something is wrong with this driver. Skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
// Get driver info details.
|
||||
driverDetailData, err := devInfoList.GetDriverInfoDetail(deviceData, driverData)
|
||||
if err != nil {
|
||||
// Something is wrong with this driver. Skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
if driverDetailData.IsCompatible(hardwareID) {
|
||||
// Matching hardware ID found.
|
||||
return wintun, nil
|
||||
}
|
||||
}
|
||||
|
||||
// This interface is not using Wintun driver.
|
||||
return nil, errors.New("Foreign network interface with the same name exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
//
|
||||
// CreateInterface creates a TUN interface.
|
||||
//
|
||||
// description is a string that supplies the text description of the device.
|
||||
// description is optional and can be "".
|
||||
//
|
||||
// hwndParent is a handle to the top-level window to use for any user
|
||||
// interface that is related to non-device-specific actions (such as a select-
|
||||
// device dialog box that uses the global class driver list). This handle is
|
||||
// optional and can be 0. If a specific top-level window is not required, set
|
||||
// hwndParent to 0.
|
||||
//
|
||||
// Function returns the network interface ID and a flag if reboot is required.
|
||||
//
|
||||
func CreateInterface(description string, hwndParent uintptr) (*Wintun, bool, error) {
|
||||
// Create an empty device info set for network adapter device class.
|
||||
devInfoList, err := setupapi.SetupDiCreateDeviceInfoListEx(&deviceClassNetGUID, hwndParent, machineName)
|
||||
if err != nil {
|
||||
return nil, false, errors.New(fmt.Sprintf("SetupDiCreateDeviceInfoListEx(%v) failed: ", guid.ToString(&deviceClassNetGUID)) + err.Error())
|
||||
}
|
||||
|
||||
// Get the device class name from GUID.
|
||||
className, err := setupapi.SetupDiClassNameFromGuidEx(&deviceClassNetGUID, machineName)
|
||||
if err != nil {
|
||||
return nil, false, errors.New(fmt.Sprintf("SetupDiClassNameFromGuidEx(%v) failed: ", guid.ToString(&deviceClassNetGUID)) + err.Error())
|
||||
}
|
||||
|
||||
// Create a new device info element and add it to the device info set.
|
||||
deviceData, err := devInfoList.CreateDeviceInfo(className, &deviceClassNetGUID, description, hwndParent, setupapi.DICD_GENERATE_ID)
|
||||
if err != nil {
|
||||
return nil, false, errors.New("SetupDiCreateDeviceInfo failed: " + err.Error())
|
||||
}
|
||||
|
||||
// Set a device information element as the selected member of a device information set.
|
||||
err = devInfoList.SetSelectedDevice(deviceData)
|
||||
if err != nil {
|
||||
return nil, false, errors.New("SetupDiSetSelectedDevice failed: " + err.Error())
|
||||
}
|
||||
|
||||
// Set Plug&Play device hardware ID property.
|
||||
hwid, err := syscall.UTF16FromString(hardwareID)
|
||||
if err != nil {
|
||||
return nil, false, err // syscall.UTF16FromString(hardwareID) should never fail: hardwareID is const string without NUL chars.
|
||||
}
|
||||
err = devInfoList.SetDeviceRegistryProperty(deviceData, setupapi.SPDRP_HARDWAREID, setupapi.UTF16ToBuf(append(hwid, 0)))
|
||||
if err != nil {
|
||||
return nil, false, errors.New("SetupDiSetDeviceRegistryProperty(SPDRP_HARDWAREID) failed: " + err.Error())
|
||||
}
|
||||
|
||||
// Search for the driver.
|
||||
const driverType = setupapi.SPDIT_CLASSDRIVER
|
||||
err = devInfoList.BuildDriverInfoList(deviceData, driverType)
|
||||
if err != nil {
|
||||
return nil, false, errors.New("SetupDiBuildDriverInfoList failed: " + err.Error())
|
||||
}
|
||||
defer devInfoList.DestroyDriverInfoList(deviceData, driverType)
|
||||
|
||||
driverDate := windows.Filetime{}
|
||||
driverVersion := uint64(0)
|
||||
for index := 0; ; index++ {
|
||||
// Get a driver from the list.
|
||||
driverData, err := devInfoList.EnumDriverInfo(deviceData, driverType, index)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
// Something is wrong with this driver. Skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
// Check the driver version first, since the check is trivial and will save us iterating over hardware IDs for any driver versioned prior our best match.
|
||||
if driverData.IsNewer(driverDate, driverVersion) {
|
||||
// Get driver info details.
|
||||
driverDetailData, err := devInfoList.GetDriverInfoDetail(deviceData, driverData)
|
||||
if err != nil {
|
||||
// Something is wrong with this driver. Skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
if driverDetailData.IsCompatible(hardwareID) {
|
||||
// Matching hardware ID found. Select the driver.
|
||||
err := devInfoList.SetSelectedDriver(deviceData, driverData)
|
||||
if err != nil {
|
||||
// Something is wrong with this driver. Skip it.
|
||||
continue
|
||||
}
|
||||
|
||||
driverDate = driverData.DriverDate
|
||||
driverVersion = driverData.DriverVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if driverVersion == 0 {
|
||||
return nil, false, fmt.Errorf("No driver for device %q installed", hardwareID)
|
||||
}
|
||||
|
||||
// Call appropriate class installer.
|
||||
err = devInfoList.CallClassInstaller(setupapi.DIF_REGISTERDEVICE, deviceData)
|
||||
if err != nil {
|
||||
return nil, false, errors.New("SetupDiCallClassInstaller(DIF_REGISTERDEVICE) failed: " + err.Error())
|
||||
}
|
||||
|
||||
// Register device co-installers if any. (Ignore errors)
|
||||
devInfoList.CallClassInstaller(setupapi.DIF_REGISTER_COINSTALLERS, deviceData)
|
||||
|
||||
// Install interfaces if any. (Ignore errors)
|
||||
devInfoList.CallClassInstaller(setupapi.DIF_INSTALLINTERFACES, deviceData)
|
||||
|
||||
var wintun *Wintun
|
||||
var rebootRequired bool
|
||||
|
||||
// Install the device.
|
||||
err = devInfoList.CallClassInstaller(setupapi.DIF_INSTALLDEVICE, deviceData)
|
||||
if err != nil {
|
||||
err = errors.New("SetupDiCallClassInstaller(DIF_INSTALLDEVICE) failed: " + err.Error())
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
// Check if a system reboot is required. (Ignore errors)
|
||||
if ret, _ := checkReboot(devInfoList, deviceData); ret {
|
||||
rebootRequired = true
|
||||
}
|
||||
|
||||
// Get network interface. DIF_INSTALLDEVICE returns almost immediately, while the device
|
||||
// installation continues in the background. It might take a while, before all registry
|
||||
// keys and values are populated.
|
||||
for numAttempts := 0; numAttempts < 30; numAttempts++ {
|
||||
wintun, err = MakeWintun(devInfoList, deviceData)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == windows.ERROR_FILE_NOT_FOUND {
|
||||
// Wait and retry. TODO: Wait for a cancellable event instead.
|
||||
err = errors.New("Time-out waiting for adapter to get ready")
|
||||
time.Sleep(time.Second / 4)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
return wintun, rebootRequired, nil
|
||||
}
|
||||
|
||||
// The interface failed to install, or the interface ID was unobtainable. Clean-up.
|
||||
removeDeviceParams := setupapi.RemoveDeviceParams{
|
||||
ClassInstallHeader: *setupapi.MakeClassInstallHeader(setupapi.DIF_REMOVE),
|
||||
Scope: setupapi.DI_REMOVEDEVICE_GLOBAL,
|
||||
}
|
||||
|
||||
// Set class installer parameters for DIF_REMOVE.
|
||||
if devInfoList.SetClassInstallParams(deviceData, &removeDeviceParams.ClassInstallHeader, uint32(unsafe.Sizeof(removeDeviceParams))) == nil {
|
||||
// Call appropriate class installer.
|
||||
if devInfoList.CallClassInstaller(setupapi.DIF_REMOVE, deviceData) == nil {
|
||||
// Check if a system reboot is required. (Ignore errors)
|
||||
if ret, _ := checkReboot(devInfoList, deviceData); ret {
|
||||
rebootRequired = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, rebootRequired, err
|
||||
}
|
||||
|
||||
//
|
||||
// DeleteInterface deletes a TUN interface.
|
||||
//
|
||||
// hwndParent is a handle to the top-level window to use for any user
|
||||
// interface that is related to non-device-specific actions (such as a select-
|
||||
// device dialog box that uses the global class driver list). This handle is
|
||||
// optional and can be 0. If a specific top-level window is not required, set
|
||||
// hwndParent to 0.
|
||||
//
|
||||
// Function returns true if the interface was found and deleted and a flag if
|
||||
// reboot is required.
|
||||
//
|
||||
func (wintun *Wintun) DeleteInterface(hwndParent uintptr) (bool, bool, error) {
|
||||
// Create a list of network devices.
|
||||
devInfoList, err := setupapi.SetupDiGetClassDevsEx(&deviceClassNetGUID, enumerator, hwndParent, setupapi.DIGCF_PRESENT, setupapi.DevInfo(0), machineName)
|
||||
if err != nil {
|
||||
return false, false, errors.New(fmt.Sprintf("SetupDiGetClassDevsEx(%v) failed: ", guid.ToString(&deviceClassNetGUID)) + err.Error())
|
||||
}
|
||||
defer devInfoList.Close()
|
||||
|
||||
// Iterate.
|
||||
for index := 0; ; index++ {
|
||||
// Get the device from the list. Should anything be wrong with this device, continue with next.
|
||||
deviceData, err := devInfoList.EnumDeviceInfo(index)
|
||||
if err != nil {
|
||||
if errWin, ok := err.(syscall.Errno); ok && errWin == 259 /*ERROR_NO_MORE_ITEMS*/ {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Get interface ID.
|
||||
wintun2, err := MakeWintun(devInfoList, deviceData)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if wintun.CfgInstanceID == wintun2.CfgInstanceID {
|
||||
// Remove the device.
|
||||
removeDeviceParams := setupapi.RemoveDeviceParams{
|
||||
ClassInstallHeader: *setupapi.MakeClassInstallHeader(setupapi.DIF_REMOVE),
|
||||
Scope: setupapi.DI_REMOVEDEVICE_GLOBAL,
|
||||
}
|
||||
|
||||
// Set class installer parameters for DIF_REMOVE.
|
||||
err = devInfoList.SetClassInstallParams(deviceData, &removeDeviceParams.ClassInstallHeader, uint32(unsafe.Sizeof(removeDeviceParams)))
|
||||
if err != nil {
|
||||
return false, false, errors.New("SetupDiSetClassInstallParams failed: " + err.Error())
|
||||
}
|
||||
|
||||
// Call appropriate class installer.
|
||||
err = devInfoList.CallClassInstaller(setupapi.DIF_REMOVE, deviceData)
|
||||
if err != nil {
|
||||
return false, false, errors.New("SetupDiCallClassInstaller failed: " + err.Error())
|
||||
}
|
||||
|
||||
// Check if a system reboot is required. (Ignore errors)
|
||||
if ret, _ := checkReboot(devInfoList, deviceData); ret {
|
||||
return true, true, nil
|
||||
}
|
||||
|
||||
return true, false, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, false, nil
|
||||
}
|
||||
|
||||
//
|
||||
// FlushInterface removes all properties from the interface and gives it only a very
|
||||
// vanilla IPv4 and IPv6 configuration with no addresses of any sort assigned.
|
||||
//
|
||||
func (wintun *Wintun) FlushInterface() error {
|
||||
//TODO: implement me!
|
||||
return nil
|
||||
}
|
||||
|
||||
//
|
||||
// checkReboot checks device install parameters if a system reboot is required.
|
||||
//
|
||||
func checkReboot(deviceInfoSet setupapi.DevInfo, deviceInfoData *setupapi.DevInfoData) (bool, error) {
|
||||
devInstallParams, err := deviceInfoSet.GetDeviceInstallParams(deviceInfoData)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if (devInstallParams.Flags & (setupapi.DI_NEEDREBOOT | setupapi.DI_NEEDRESTART)) != 0 {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
//
|
||||
// GetInterfaceName returns network interface name.
|
||||
//
|
||||
func (wintun *Wintun) GetInterfaceName() (string, error) {
|
||||
key, err := registryOpenKeyRetry(registry.LOCAL_MACHINE, wintun.GetNetRegKeyName(), registry.QUERY_VALUE)
|
||||
if err != nil {
|
||||
return "", errors.New("Network-specific registry key open failed: " + err.Error())
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
// Get the interface name.
|
||||
return getRegStringValue(key, "Name")
|
||||
}
|
||||
|
||||
//
|
||||
// SetInterfaceName sets network interface name.
|
||||
//
|
||||
func (wintun *Wintun) SetInterfaceName(ifname string) error {
|
||||
// We open the registry key before calling HrRename, because the registry open will wait until the key exists.
|
||||
key, err := registryOpenKeyRetry(registry.LOCAL_MACHINE, wintun.GetNetRegKeyName(), registry.SET_VALUE)
|
||||
if err != nil {
|
||||
return errors.New("Network-specific registry key open failed: " + err.Error())
|
||||
}
|
||||
defer key.Close()
|
||||
|
||||
// We have to tell the various runtime COM services about the new name too. We ignore the
|
||||
// error because netshell isn't available on servercore.
|
||||
// TODO: netsh.exe falls back to NciSetConnection in this case. If somebody complains, maybe
|
||||
// we should do the same.
|
||||
_ = netshell.HrRenameConnection(&wintun.CfgInstanceID, windows.StringToUTF16Ptr(ifname))
|
||||
|
||||
// Set the interface name. The above line should have done this too, but in case it failed, we force it.
|
||||
return key.SetStringValue("Name", ifname)
|
||||
}
|
||||
|
||||
//
|
||||
// GetNetRegKeyName returns interface-specific network registry key name.
|
||||
//
|
||||
func (wintun *Wintun) GetNetRegKeyName() string {
|
||||
return fmt.Sprintf("SYSTEM\\CurrentControlSet\\Control\\Network\\%v\\%v\\Connection", guid.ToString(&deviceClassNetGUID), guid.ToString(&wintun.CfgInstanceID))
|
||||
}
|
||||
|
||||
//
|
||||
// getRegStringValue function reads a string value from registry.
|
||||
//
|
||||
// If the value type is REG_EXPAND_SZ the environment variables are expanded.
|
||||
// Should expanding fail, original string value and nil error are returned.
|
||||
//
|
||||
func getRegStringValue(key registry.Key, name string) (string, error) {
|
||||
// Read string value.
|
||||
value, valueType, err := keyGetStringValueRetry(key, name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if valueType != registry.EXPAND_SZ {
|
||||
// Value does not require expansion.
|
||||
return value, nil
|
||||
}
|
||||
|
||||
valueExp, err := registry.ExpandString(value)
|
||||
if err != nil {
|
||||
// Expanding failed: return original sting value.
|
||||
return value, nil
|
||||
}
|
||||
|
||||
// Return expanded value.
|
||||
return valueExp, nil
|
||||
}
|
||||
|
||||
//
|
||||
// DataFileName returns Wintun device data pipe name.
|
||||
//
|
||||
func (wintun *Wintun) DataFileName() string {
|
||||
return fmt.Sprintf("\\\\.\\Global\\WINTUN%d", wintun.LUIDIndex)
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
package main
|
||||
const WireGuardGoVersion = "0.0.20181222"
|
||||
Reference in New Issue
Block a user