diff options
37 files changed, 2030 insertions, 600 deletions
@@ -1,235 +1,616 @@ | |||
1 | GNU AFFERO GENERAL PUBLIC LICENSE | 1 | GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 |
2 | Version 3, 19 November 2007 | 2 | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
3 | |||
4 | Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | ||
5 | 3 | ||
6 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. | 4 | Everyone is permitted to copy and distribute verbatim copies of this license |
7 | 5 | document, but changing it is not allowed. | |
8 | Preamble | 6 | |
9 | 7 | Preamble | |
10 | The GNU Affero General Public License is a free, copyleft license for software and other kinds of works, specifically designed to ensure cooperation with the community in the case of network server software. | 8 | |
11 | 9 | The GNU Affero General Public License is a free, copyleft license for software | |
12 | The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, our General Public Licenses are intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. | 10 | and other kinds of works, specifically designed to ensure cooperation with the |
13 | 11 | community in the case of network server software. | |
14 | When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. | 12 | |
15 | 13 | The licenses for most software and other practical works are designed to take | |
16 | Developers that use our General Public Licenses protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License which gives you legal permission to copy, distribute and/or modify the software. | 14 | away your freedom to share and change the works. By contrast, our General |
17 | 15 | Public Licenses are intended to guarantee your freedom to share and change all | |
18 | A secondary benefit of defending all users' freedom is that improvements made in alternate versions of the program, if they receive widespread use, become available for other developers to incorporate. Many developers of free software are heartened and encouraged by the resulting cooperation. However, in the case of software used on network servers, this result may fail to come about. The GNU General Public License permits making a modified version and letting the public access it on a server without ever releasing its source code to the public. | 16 | versions of a program--to make sure it remains free software for all its users. |
19 | 17 | ||
20 | The GNU Affero General Public License is designed specifically to ensure that, in such cases, the modified source code becomes available to the community. It requires the operator of a network server to provide the source code of the modified version running there to the users of that server. Therefore, public use of a modified version, on a publicly accessible server, gives the public access to the source code of the modified version. | 18 | When we speak of free software, we are referring to freedom, not price. Our |
21 | 19 | General Public Licenses are designed to make sure that you have the freedom to | |
22 | An older license, called the Affero General Public License and published by Affero, was designed to accomplish similar goals. This is a different license, not a version of the Affero GPL, but Affero has released a new version of the Affero GPL which permits relicensing under this license. | 20 | distribute copies of free software (and charge for them if you wish), that you |
23 | 21 | receive source code or can get it if you want it, that you can change the | |
24 | The precise terms and conditions for copying, distribution and modification follow. | 22 | software or use pieces of it in new free programs, and that you know you can |
25 | 23 | do these things. | |
26 | TERMS AND CONDITIONS | 24 | |
27 | 25 | Developers that use our General Public Licenses protect your rights with two | |
28 | 0. Definitions. | 26 | steps: (1) assert copyright on the software, and (2) offer you this License |
29 | 27 | which gives you legal permission to copy, distribute and/or modify the software. | |
30 | "This License" refers to version 3 of the GNU Affero General Public License. | 28 | |
31 | 29 | A secondary benefit of defending all users' freedom is that improvements made | |
32 | "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. | 30 | in alternate versions of the program, if they receive widespread use, become |
33 | 31 | available for other developers to incorporate. Many developers of free | |
34 | "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. | 32 | software are heartened and encouraged by the resulting cooperation. However, |
35 | 33 | in the case of software used on network servers, this result may fail to come | |
36 | To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. | 34 | about. The GNU General Public License permits making a modified version and |
37 | 35 | letting the public access it on a server without ever releasing its source code | |
38 | A "covered work" means either the unmodified Program or a work based on the Program. | 36 | to the public. |
39 | 37 | ||
40 | To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. | 38 | The GNU Affero General Public License is designed specifically to ensure that, |
41 | 39 | in such cases, the modified source code becomes available to the community. It | |
42 | To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. | 40 | requires the operator of a network server to provide the source code of the |
43 | 41 | modified version running there to the users of that server. Therefore, public | |
44 | An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. | 42 | use of a modified version, on a publicly accessible server, gives the public |
45 | 43 | access to the source code of the modified version. | |
46 | 1. Source Code. | 44 | |
47 | The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. | 45 | An older license, called the Affero General Public License and published by |
48 | 46 | Affero, was designed to accomplish similar goals. This is a different license, | |
49 | A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. | 47 | not a version of the Affero GPL, but Affero has released a new version of the |
50 | 48 | Affero GPL which permits relicensing under this license. | |
51 | The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. | 49 | |
52 | 50 | The precise terms and conditions for copying, distribution and modification | |
53 | The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those | 51 | follow. |
54 | subprograms and other parts of the work. | 52 | |
55 | 53 | TERMS AND CONDITIONS | |
56 | The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. | 54 | |
57 | 55 | 0. Definitions. | |
58 | The Corresponding Source for a work in source code form is that same work. | 56 | |
59 | 57 | "This License" refers to version 3 of the GNU Affero General Public License. | |
60 | 2. Basic Permissions. | 58 | |
61 | All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. | 59 | "Copyright" also means copyright-like laws that apply to other kinds of works, |
62 | 60 | such as semiconductor masks. | |
63 | You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. | 61 | |
64 | 62 | "The Program" refers to any copyrightable work licensed under this License. | |
65 | Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. | 63 | Each licensee is addressed as "you". "Licensees" and "recipients" may be |
66 | 64 | individuals or organizations. | |
67 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | 65 | |
68 | No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. | 66 | To "modify" a work means to copy from or adapt all or part of the work in a |
69 | 67 | fashion requiring copyright permission, other than the making of an exact copy. | |
70 | When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. | 68 | The resulting work is called a "modified version" of the earlier work or a |
71 | 69 | work "based on" the earlier work. | |
72 | 4. Conveying Verbatim Copies. | 70 | |
73 | You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. | 71 | A "covered work" means either the unmodified Program or a work based on the |
74 | 72 | Program. | |
75 | You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. | 73 | |
76 | 74 | To "propagate" a work means to do anything with it that, without permission, | |
77 | 5. Conveying Modified Source Versions. | 75 | would make you directly or secondarily liable for infringement under applicable |
78 | You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: | 76 | copyright law, except executing it on a computer or modifying a private copy. |
79 | 77 | Propagation includes copying, distribution (with or without modification), | |
80 | a) The work must carry prominent notices stating that you modified it, and giving a relevant date. | 78 | making available to the public, and in some countries other activities as well. |
81 | 79 | ||
82 | b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". | 80 | To "convey" a work means any kind of propagation that enables other parties to |
83 | 81 | make or receive copies. Mere interaction with a user through a computer | |
84 | c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. | 82 | network, with no transfer of a copy, is not conveying. |
85 | 83 | ||
86 | d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. | 84 | An interactive user interface displays "Appropriate Legal Notices" to the |
87 | 85 | extent that it includes a convenient and prominently visible feature that | |
88 | A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. | 86 | (1) displays an appropriate copyright notice, and (2) tells the user that |
89 | 87 | there is no warranty for the work (except to the extent that warranties are | |
90 | 6. Conveying Non-Source Forms. | 88 | provided), that licensees may convey the work under this License, and how to |
91 | You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: | 89 | view a copy of this License. If the interface presents a list of user commands |
92 | 90 | or options, such as a menu, a prominent item in the list meets this criterion. | |
93 | a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. | 91 | |
94 | 92 | 1. Source Code. | |
95 | b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. | 93 | |
96 | 94 | The "source code" for a work means the preferred form of the work for making | |
97 | c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. | 95 | modifications to it. "Object code" means any non-source form of a work. |
98 | 96 | ||
99 | d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. | 97 | A "Standard Interface" means an interface that either is an official standard |
100 | 98 | defined by a recognized standards body, or, in the case of interfaces specified | |
101 | e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. | 99 | for a particular programming language, one that is widely used among developers |
102 | 100 | working in that language. | |
103 | A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. | 101 | |
104 | 102 | The "System Libraries" of an executable work include anything, other than the | |
105 | A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. | 103 | work as a whole, that (a) is included in the normal form of packaging a Major |
106 | 104 | Component, but which is not part of that Major Component, and (b) serves only | |
107 | "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. | 105 | to enable use of the work with that Major Component, or to implement a Standard |
108 | 106 | Interface for which an implementation is available to the public in source code | |
109 | If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). | 107 | form. A "Major Component", in this context, means a major essential component |
110 | 108 | (kernel, window system, and so on) of the specific operating system (if any) on | |
111 | The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. | 109 | which the executable work runs, or a compiler used to produce the work, or an |
112 | 110 | object code interpreter used to run it. | |
113 | Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. | 111 | |
114 | 112 | The "Corresponding Source" for a work in object code form means all the source | |
115 | 7. Additional Terms. | 113 | code needed to generate, install, and (for an executable work) run the object |
116 | "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. | 114 | code and to modify the work, including scripts to control those activities. |
117 | 115 | However, it does not include the work's System Libraries, or general-purpose | |
118 | When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. | 116 | tools or generally available free programs which are used unmodified in |
119 | 117 | performing those activities but which are not part of the work. For example, | |
120 | Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: | 118 | Corresponding Source includes interface definition files associated with source |
121 | 119 | files for the work, and the source code for shared libraries and dynamically | |
122 | a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or | 120 | linked subprograms that the work is specifically designed to require, such as |
123 | 121 | by intimate data communication or control flow between those subprograms and | |
124 | b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or | 122 | other parts of the work. |
125 | 123 | ||
126 | c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or | 124 | The Corresponding Source need not include anything that users can regenerate |
127 | 125 | automatically from other parts of the Corresponding Source. | |
128 | d) Limiting the use for publicity purposes of names of licensors or authors of the material; or | 126 | |
129 | 127 | The Corresponding Source for a work in source code form is that same work. | |
130 | e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or | 128 | |
131 | 129 | 2. Basic Permissions. | |
132 | f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. | 130 | |
133 | 131 | All rights granted under this License are granted for the term of copyright on | |
134 | All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. | 132 | the Program, and are irrevocable provided the stated conditions are met. This |
135 | 133 | License explicitly affirms your unlimited permission to run the unmodified | |
136 | If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. | 134 | Program. The output from running a covered work is covered by this License |
137 | 135 | only if the output, given its content, constitutes a covered work. This | |
138 | Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. | 136 | License acknowledges your rights of fair use or other equivalent, as provided |
139 | 137 | by copyright law. | |
140 | 8. Termination. | 138 | |
141 | 139 | You may make, run and propagate covered works that you do not convey, without | |
142 | You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). | 140 | conditions so long as your license otherwise remains in force. You may convey |
143 | 141 | covered works to others for the sole purpose of having them make modifications | |
144 | However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. | 142 | exclusively for you, or provide you with facilities for running those works, |
145 | 143 | provided that you comply with the terms of this License in conveying all | |
146 | Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. | 144 | material for which you do not control copyright. Those thus making or running |
147 | 145 | the covered works for you must do so exclusively on your behalf, under your | |
148 | Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. | 146 | direction and control, on terms that prohibit them from making any copies of |
149 | 147 | your copyrighted material outside their relationship with you. | |
150 | 9. Acceptance Not Required for Having Copies. | 148 | |
151 | 149 | Conveying under any other circumstances is permitted solely under the | |
152 | You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. | 150 | conditions stated below. Sublicensing is not allowed; section 10 makes it |
153 | 151 | unnecessary. | |
154 | 10. Automatic Licensing of Downstream Recipients. | 152 | |
155 | 153 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | |
156 | Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. | 154 | |
157 | 155 | No covered work shall be deemed part of an effective technological measure | |
158 | An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. | 156 | under any applicable law fulfilling obligations under article 11 of the WIPO |
159 | 157 | copyright treaty adopted on 20 December 1996, or similar laws prohibiting or | |
160 | You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. | 158 | restricting circumvention of such measures. |
161 | 159 | ||
162 | 11. Patents. | 160 | When you convey a covered work, you waive any legal power to forbid |
163 | 161 | circumvention of technological measures to the extent such circumvention is | |
164 | A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". | 162 | effected by exercising rights under this License with respect to the covered |
165 | 163 | work, and you disclaim any intention to limit operation or modification of the | |
166 | A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. | 164 | work as a means of enforcing, against the work's users, your or third parties' |
167 | 165 | legal rights to forbid circumvention of technological measures. | |
168 | Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. | 166 | |
169 | 167 | 4. Conveying Verbatim Copies. | |
170 | In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to s ue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. | 168 | |
171 | 169 | You may convey verbatim copies of the Program's source code as you receive it, | |
172 | If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent | 170 | in any medium, provided that you conspicuously and appropriately publish on |
173 | license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. | 171 | each copy an appropriate copyright notice; keep intact all notices stating |
174 | 172 | that this License and any non-permissive terms added in accord with section | |
175 | If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. | 173 | 7 apply to the code; keep intact all notices of the absence of any warranty; |
176 | 174 | and give all recipients a copy of this License along with the Program. | |
177 | A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. | 175 | |
178 | 176 | You may charge any price or no price for each copy that you convey, and you | |
179 | Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. | 177 | may offer support or warranty protection for a fee. |
180 | 178 | ||
181 | 12. No Surrender of Others' Freedom. | 179 | 5. Conveying Modified Source Versions. |
182 | 180 | ||
183 | If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may | 181 | You may convey a work based on the Program, or the modifications to produce it |
184 | not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. | 182 | from the Program, in the form of source code under the terms of section 4, |
185 | 183 | provided that you also meet all of these conditions: | |
186 | 13. Remote Network Interaction; Use with the GNU General Public License. | 184 | |
187 | 185 | a) The work must carry prominent notices stating that you modified it, and | |
188 | Notwithstanding any other provision of this License, if you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network (if your version supports such interaction) an opportunity to receive the Corresponding Source of your version by providing access to the Corresponding Source from a network server at no charge, through some standard or customary means of facilitating copying of software. This Corresponding Source shall include the Corresponding Source for any work covered by version 3 of the GNU General Public License that is incorporated pursuant to the following paragraph. | 186 | giving a relevant date. |
189 | 187 | ||
190 | Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the work with which it is combined will remain governed by version 3 of the GNU General Public License. | 188 | b) The work must carry prominent notices stating that it is released under |
191 | 189 | this License and any conditions added under section 7. This requirement | |
192 | 14. Revised Versions of this License. | 190 | modifies the requirement in section 4 to "keep intact all notices". |
193 | 191 | ||
194 | The Free Software Foundation may publish revised and/or new versions of the GNU Affero 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. | 192 | c) You must license the entire work, as a whole, under this License to |
195 | 193 | anyone who comes into possession of a copy. This License will | |
196 | Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU Affero General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU Affero General Public License, you may choose any version ever published by the Free Software Foundation. | 194 | therefore apply, along with any applicable section 7 additional terms, |
197 | 195 | to the whole of the work, and all its parts, regardless of how they are | |
198 | If the Program specifies that a proxy can decide which future versions of the GNU Affero General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. | 196 | packaged. This License gives no permission to license the work in any |
199 | 197 | other way, but it does not invalidate such permission if you have | |
200 | Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. | 198 | separately received it. |
201 | 199 | ||
202 | 15. Disclaimer of Warranty. | 200 | d) If the work has interactive user interfaces, each must display |
203 | 201 | Appropriate Legal Notices; however, if the Program has interactive | |
204 | 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. | 202 | interfaces that do not display Appropriate Legal Notices, your work |
205 | 203 | need not make them do so. | |
206 | 16. Limitation of Liability. | 204 | |
207 | 205 | A compilation of a covered work with other separate and independent works, | |
208 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | 206 | which are not by their nature extensions of the covered work, and which are |
209 | 207 | not combined with it such as to form a larger program, in or on a volume of a | |
210 | 17. Interpretation of Sections 15 and 16. | 208 | storage or distribution medium, is called an "aggregate" if the compilation |
211 | 209 | and its resulting copyright are not used to limit the access or legal rights | |
212 | If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. | 210 | of the compilation's users beyond what the individual works permit. Inclusion |
213 | 211 | of a covered work in an aggregate does not cause this License to apply to the | |
214 | END OF TERMS AND CONDITIONS | 212 | other parts of the aggregate. |
215 | 213 | ||
216 | How to Apply These Terms to Your New Programs | 214 | 6. Conveying Non-Source Forms. |
217 | 215 | ||
218 | 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. | 216 | You may convey a covered work in object code form under the terms of sections |
219 | 217 | 4 and 5, provided that you also convey the machine-readable Corresponding | |
220 | To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. | 218 | Source under the terms of this License, in one of these ways: |
221 | 219 | ||
222 | <one line to give the program's name and a brief idea of what it does.> | 220 | a) Convey the object code in, or embodied in, a physical product |
223 | Copyright (C) <year> <name of author> | 221 | (including a physical distribution medium), accompanied by the |
224 | 222 | Corresponding Source fixed on a durable physical medium customarily | |
225 | This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. | 223 | used for software interchange. |
226 | 224 | ||
227 | 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 Affero General Public License for more details. | 225 | b) Convey the object code in, or embodied in, a physical product |
228 | 226 | (including a physical distribution medium), accompanied by a written | |
229 | You should have received a copy of the GNU Affero General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. | 227 | offer, valid for at least three years and valid for as long as you |
230 | 228 | offer spare parts or customer support for that product model, to give | |
231 | Also add information on how to contact you by electronic and paper mail. | 229 | anyone who possesses the object code either (1) a copy of the |
232 | 230 | Corresponding Source for all the software in the product that is | |
233 | If your software can interact with users remotely through a computer network, you should also make sure that it provides a way for users to get its source. For example, if your program is a web application, its interface could display a "Source" link that leads users to an archive of the code. There are many ways you could offer source, and different solutions will be better for different programs; see section 13 for the specific requirements. | 231 | covered by this License, on a durable physical medium customarily used |
234 | 232 | for software interchange, for a price no more than your reasonable cost | |
235 | You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see <http://www.gnu.org/licenses/>. \ No newline at end of file | 233 | of physically performing this conveying of source, or (2) access to |
234 | copy the Corresponding Source from a network server at no charge. | ||
235 | |||
236 | c) Convey individual copies of the object code with a copy of the written | ||
237 | offer to provide the Corresponding Source. This alternative is allowed | ||
238 | only occasionally and noncommercially, and only if you received the | ||
239 | object code with such an offer, in accord with subsection 6b. | ||
240 | |||
241 | d) Convey the object code by offering access from a designated place | ||
242 | (gratis or for a charge), and offer equivalent access to the | ||
243 | Corresponding Source in the same way through the same place at no | ||
244 | further charge. You need not require recipients to copy the | ||
245 | Corresponding Source along with the object code. If the place to copy | ||
246 | the object code is a network server, the Corresponding Source may be on | ||
247 | a different server (operated by you or a third party) that supports | ||
248 | equivalent copying facilities, provided you maintain clear directions | ||
249 | next to the object code saying where to find the Corresponding Source. | ||
250 | Regardless of what server hosts the Corresponding Source, you remain | ||
251 | obligated to ensure that it is available for as long as needed to | ||
252 | satisfy these requirements. | ||
253 | |||
254 | e) Convey the object code using peer-to-peer transmission, provided you | ||
255 | inform other peers where the object code and Corresponding Source of | ||
256 | the work are being offered to the general public at no charge under | ||
257 | subsection 6d. | ||
258 | |||
259 | A separable portion of the object code, whose source code is excluded from the | ||
260 | Corresponding Source as a System Library, need not be included in conveying | ||
261 | the object code work. | ||
262 | |||
263 | A "User Product" is either (1) a "consumer product", which means any tangible | ||
264 | personal property which is normally used for personal, family, or household | ||
265 | purposes, or (2) anything designed or sold for incorporation into a dwelling. | ||
266 | In determining whether a product is a consumer product, doubtful cases shall | ||
267 | be resolved in favor of coverage. For a particular product received by a | ||
268 | particular user, "normally used" refers to a typical or common use of that | ||
269 | class of product, regardless of the status of the particular user or of the | ||
270 | way in which the particular user actually uses, or expects or is expected to | ||
271 | use, the product. A product is a consumer product regardless of whether the | ||
272 | product has substantial commercial, industrial or non-consumer uses, unless | ||
273 | such uses represent the only significant mode of use of the product. | ||
274 | |||
275 | "Installation Information" for a User Product means any methods, procedures, | ||
276 | authorization keys, or other information required to install and execute | ||
277 | modified versions of a covered work in that User Product from a modified | ||
278 | version of its Corresponding Source. The information must suffice to ensure | ||
279 | that the continued functioning of the modified object code is in no case | ||
280 | prevented or interfered with solely because modification has been made. | ||
281 | |||
282 | If you convey an object code work under this section in, or with, or | ||
283 | specifically for use in, a User Product, and the conveying occurs as part of | ||
284 | a transaction in which the right of possession and use of the User Product is | ||
285 | transferred to the recipient in perpetuity or for a fixed term (regardless of | ||
286 | how the transaction is characterized), the Corresponding Source conveyed under | ||
287 | this section must be accompanied by the Installation Information. But this | ||
288 | requirement does not apply if neither you nor any third party retains the | ||
289 | ability to install modified object code on the User Product (for example, the | ||
290 | work has been installed in ROM). | ||
291 | |||
292 | The requirement to provide Installation Information does not include a | ||
293 | requirement to continue to provide support service, warranty, or updates for a | ||
294 | work that has been modified or installed by the recipient, or for the User | ||
295 | Product in which it has been modified or installed. Access to a network may | ||
296 | be denied when the modification itself materially and adversely affects the | ||
297 | operation of the network or violates the rules and protocols for communication | ||
298 | across the network. | ||
299 | |||
300 | Corresponding Source conveyed, and Installation Information provided, in | ||
301 | accord with this section must be in a format that is publicly documented (and | ||
302 | with an implementation available to the public in source code form), and must | ||
303 | require no special password or key for unpacking, reading or copying. | ||
304 | |||
305 | 7. Additional Terms. | ||
306 | |||
307 | "Additional permissions" are terms that supplement the terms of this License | ||
308 | by making exceptions from one or more of its conditions. Additional permissions | ||
309 | that are applicable to the entire Program shall be treated as though they were | ||
310 | included in this License, to the extent that they are valid under applicable | ||
311 | law. If additional permissions apply only to part of the Program, that part | ||
312 | may be used separately under those permissions, but the entire Program remains | ||
313 | governed by this License without regard to the additional permissions. | ||
314 | |||
315 | When you convey a copy of a covered work, you may at your option remove any | ||
316 | additional permissions from that copy, or from any part of it. (Additional | ||
317 | permissions may be written to require their own removal in certain cases when | ||
318 | you modify the work.) You may place additional permissions on material, added | ||
319 | by you to a covered work, for which you have or can give appropriate copyright | ||
320 | permission. | ||
321 | |||
322 | Notwithstanding any other provision of this License, for material you add to a | ||
323 | covered work, you may (if authorized by the copyright holders of that material) | ||
324 | supplement the terms of this License with terms: | ||
325 | |||
326 | a) Disclaiming warranty or limiting liability differently from the terms of | ||
327 | sections 15 and 16 of this License; or | ||
328 | |||
329 | b) Requiring preservation of specified reasonable legal notices or author | ||
330 | attributions in that material or in the Appropriate Legal Notices | ||
331 | displayed by works containing it; or | ||
332 | |||
333 | c) Prohibiting misrepresentation of the origin of that material, or | ||
334 | requiring that modified versions of such material be marked in | ||
335 | reasonable ways as different from the original version; or | ||
336 | |||
337 | d) Limiting the use for publicity purposes of names of licensors or authors | ||
338 | of the material; or | ||
339 | |||
340 | e) Declining to grant rights under trademark law for use of some trade | ||
341 | names, trademarks, or service marks; or | ||
342 | |||
343 | f) Requiring indemnification of licensors and authors of that material by | ||
344 | anyone who conveys the material (or modified versions of it) with | ||
345 | contractual assumptions of liability to the recipient, for any liability | ||
346 | that these contractual assumptions directly impose on those licensors | ||
347 | and authors. | ||
348 | |||
349 | All other non-permissive additional terms are considered "further restrictions" | ||
350 | within the meaning of section 10. If the Program as you received it, or any | ||
351 | part of it, contains a notice stating that it is governed by this License along | ||
352 | with a term that is a further restriction, you may remove that term. If a | ||
353 | license document contains a further restriction but permits relicensing or | ||
354 | conveying under this License, you may add to a covered work material governed | ||
355 | by the terms of that license document, provided that the further restriction | ||
356 | does not survive such relicensing or conveying. | ||
357 | |||
358 | If you add terms to a covered work in accord with this section, you must place, | ||
359 | in the relevant source files, a statement of the additional terms that apply | ||
360 | to those files, or a notice indicating where to find the applicable terms. | ||
361 | |||
362 | Additional terms, permissive or non-permissive, may be stated in the form of a | ||
363 | separately written license, or stated as exceptions; the above requirements | ||
364 | apply either way. | ||
365 | |||
366 | 8. Termination. | ||
367 | |||
368 | You may not propagate or modify a covered work except as expressly provided | ||
369 | under this License. Any attempt otherwise to propagate or modify it is void, | ||
370 | and will automatically terminate your rights under this License (including any | ||
371 | patent licenses granted under the third paragraph of section 11). | ||
372 | |||
373 | However, if you cease all violation of this License, then your license from a | ||
374 | particular copyright holder is reinstated (a) provisionally, unless and until | ||
375 | the copyright holder explicitly and finally terminates your license, and (b) | ||
376 | permanently, if the copyright holder fails to notify you of the violation by | ||
377 | some reasonable means prior to 60 days after the cessation. | ||
378 | |||
379 | Moreover, your license from a particular copyright holder is reinstated | ||
380 | permanently if the copyright holder notifies you of the violation by some | ||
381 | reasonable means, this is the first time you have received notice of violation | ||
382 | of this License (for any work) from that copyright holder, and you cure the | ||
383 | violation prior to 30 days after your receipt of the notice. | ||
384 | |||
385 | Termination of your rights under this section does not terminate the licenses | ||
386 | of parties who have received copies or rights from you under this License. | ||
387 | If your rights have been terminated and not permanently reinstated, you do not | ||
388 | qualify to receive new licenses for the same material under section 10. | ||
389 | |||
390 | 9. Acceptance Not Required for Having Copies. | ||
391 | |||
392 | You are not required to accept this License in order to receive or run a copy | ||
393 | of the Program. Ancillary propagation of a covered work occurring solely as a | ||
394 | consequence of using peer-to-peer transmission to receive a copy likewise does | ||
395 | not require acceptance. However, nothing other than this License grants you | ||
396 | permission to propagate or modify any covered work. These actions infringe | ||
397 | copyright if you do not accept this License. Therefore, by modifying or | ||
398 | propagating a covered work, you indicate your acceptance of this License to | ||
399 | do so. | ||
400 | |||
401 | 10. Automatic Licensing of Downstream Recipients. | ||
402 | |||
403 | Each time you convey a covered work, the recipient automatically receives a | ||
404 | license from the original licensors, to run, modify and propagate that work, | ||
405 | subject to this License. You are not responsible for enforcing compliance by | ||
406 | third parties with this License. | ||
407 | |||
408 | An "entity transaction" is a transaction transferring control of an | ||
409 | organization, or substantially all assets of one, or subdividing an | ||
410 | organization, or merging organizations. If propagation of a covered work | ||
411 | results from an entity transaction, each party to that transaction who receives | ||
412 | a copy of the work also receives whatever licenses to the work the party's | ||
413 | predecessor in interest had or could give under the previous paragraph, plus a | ||
414 | right to possession of the Corresponding Source of the work from the | ||
415 | predecessor in interest, if the predecessor has it or can get it with | ||
416 | reasonable efforts. | ||
417 | |||
418 | You may not impose any further restrictions on the exercise of the rights | ||
419 | granted or affirmed under this License. For example, you may not impose a | ||
420 | license fee, royalty, or other charge for exercise of rights granted under this | ||
421 | License, and you may not initiate litigation (including a cross-claim or | ||
422 | counterclaim in a lawsuit) alleging that any patent claim is infringed by | ||
423 | making, using, selling, offering for sale, or importing the Program or any | ||
424 | portion of it. | ||
425 | |||
426 | 11. Patents. | ||
427 | |||
428 | A "contributor" is a copyright holder who authorizes use under this License of | ||
429 | the Program or a work on which the Program is based. The work thus licensed is | ||
430 | called the contributor's "contributor version". | ||
431 | |||
432 | A contributor's "essential patent claims" are all patent claims owned or | ||
433 | controlled by the contributor, whether already acquired or hereafter acquired, | ||
434 | that would be infringed by some manner, permitted by this License, of making, | ||
435 | using, or selling its contributor version, but do not include claims that would | ||
436 | be infringed only as a consequence of further modification of the contributor | ||
437 | version. For purposes of this definition, "control" includes the right to | ||
438 | grant patent sublicenses in a manner consistent with the requirements of this | ||
439 | License. | ||
440 | |||
441 | Each contributor grants you a non-exclusive, worldwide, royalty-free patent | ||
442 | license under the contributor's essential patent claims, to make, use, sell, | ||
443 | offer for sale, import and otherwise run, modify and propagate the contents of | ||
444 | its contributor version. | ||
445 | |||
446 | In the following three paragraphs, a "patent license" is any express agreement | ||
447 | or commitment, however denominated, not to enforce a patent (such as an express | ||
448 | permission to practice a patent or covenant not to s ue for patent | ||
449 | infringement). To "grant" such a patent license to a party means to make such an | ||
450 | agreement or commitment not to enforce a patent against the party. | ||
451 | |||
452 | If you convey a covered work, knowingly relying on a patent license, and the | ||
453 | Corresponding Source of the work is not available for anyone to copy, free of | ||
454 | charge and under the terms of this License, through a publicly available | ||
455 | network server or other readily accessible means, then you must either | ||
456 | (1) cause the Corresponding Source to be so available, or (2) arrange to | ||
457 | deprive yourself of the benefit of the patent license for this particular work, | ||
458 | or (3) arrange, in a manner consistent with the requirements of this License, | ||
459 | to extend the patent license to downstream recipients. "Knowingly relying" | ||
460 | means you have actual knowledge that, but for the patent license, your | ||
461 | conveying the covered work in a country, or your recipient's use of the | ||
462 | covered work in a country, would infringe one or more identifiable patents in | ||
463 | that country that you have reason to believe are valid. | ||
464 | |||
465 | If, pursuant to or in connection with a single transaction or arrangement, you | ||
466 | convey, or propagate by procuring conveyance of, a covered work, and grant a | ||
467 | patent license to some of the parties receiving the covered work authorizing | ||
468 | them to use, propagate, modify or convey a specific copy of the covered work, | ||
469 | then the patent license you grant is automatically extended to all recipients | ||
470 | of the covered work and works based on it. | ||
471 | |||
472 | A patent license is "discriminatory" if it does not include within the scope of | ||
473 | its coverage, prohibits the exercise of, or is conditioned on the non-exercise | ||
474 | of one or more of the rights that are specifically granted under this License. | ||
475 | You may not convey a covered work if you are a party to an arrangement with a | ||
476 | third party that is in the business of distributing software, under which you | ||
477 | make payment to the third party based on the extent of your activity of | ||
478 | conveying the work, and under which the third party grants, to any of the | ||
479 | parties who would receive the covered work from you, a discriminatory patent | ||
480 | license (a) in connection with copies of the covered work conveyed by you (or | ||
481 | copies made from those copies), or (b) primarily for and in connection with | ||
482 | specific products or compilations that contain the covered work, unless you | ||
483 | entered into that arrangement, or that patent license was granted, prior to | ||
484 | 28 March 2007. | ||
485 | |||
486 | Nothing in this License shall be construed as excluding or limiting any implied | ||
487 | license or other defenses to infringement that may otherwise be available to | ||
488 | you under applicable patent law. | ||
489 | |||
490 | 12. No Surrender of Others' Freedom. | ||
491 | |||
492 | If conditions are imposed on you (whether by court order, agreement or | ||
493 | otherwise) that contradict the conditions of this License, they do not excuse | ||
494 | you from the conditions of this License. If you cannot convey a covered work | ||
495 | so as to satisfy simultaneously your obligations under this License and any | ||
496 | other pertinent obligations, then as a consequence you may not convey it at | ||
497 | all. For example, if you agree to terms that obligate you to collect a royalty | ||
498 | for further conveying from those to whom you convey the Program, the only way | ||
499 | you could satisfy both those terms and this License would be to refrain | ||
500 | entirely from conveying the Program. | ||
501 | |||
502 | 13. Remote Network Interaction; Use with the GNU General Public License. | ||
503 | |||
504 | Notwithstanding any other provision of this License, if you modify the Program, | ||
505 | your modified version must prominently offer all users interacting with it | ||
506 | remotely through a computer network (if your version supports such interaction) | ||
507 | an opportunity to receive the Corresponding Source of your version by providing | ||
508 | access to the Corresponding Source from a network server at no charge, through | ||
509 | some standard or customary means of facilitating copying of software. This | ||
510 | Corresponding Source shall include the Corresponding Source for any work | ||
511 | covered by version 3 of the GNU General Public License that is incorporated | ||
512 | pursuant to the following paragraph. | ||
513 | |||
514 | Notwithstanding any other provision of this License, you have permission to | ||
515 | link or combine any covered work with a work licensed under version 3 of the | ||
516 | GNU General Public License into a single combined work, and to convey the | ||
517 | resulting work. The terms of this License will continue to apply to the part | ||
518 | which is the covered work, but the work with which it is combined will remain | ||
519 | governed by version 3 of the GNU General Public License. | ||
520 | |||
521 | 14. Revised Versions of this License. | ||
522 | |||
523 | The Free Software Foundation may publish revised and/or new versions of the GNU | ||
524 | Affero General Public License from time to time. Such new versions will be | ||
525 | similar in spirit to the present version, but may differ in detail to address | ||
526 | new problems or concerns. | ||
527 | |||
528 | Each version is given a distinguishing version number. If the Program | ||
529 | specifies that a certain numbered version of the GNU Affero General Public | ||
530 | License "or any later version" applies to it, you have the option of | ||
531 | following the terms and conditions either of that numbered version or of any | ||
532 | later version published by the Free Software Foundation. If the Program does | ||
533 | not specify a version number of the GNU Affero General Public License, you may | ||
534 | choose any version ever published by the Free Software Foundation. | ||
535 | |||
536 | If the Program specifies that a proxy can decide which future versions of the | ||
537 | GNU Affero General Public License can be used, that proxy's public statement | ||
538 | of acceptance of a version permanently authorizes you to choose that version | ||
539 | for the Program. | ||
540 | |||
541 | Later license versions may give you additional or different permissions. | ||
542 | However, no additional obligations are imposed on any author or copyright | ||
543 | holder as a result of your choosing to follow a later version. | ||
544 | |||
545 | 15. Disclaimer of Warranty. | ||
546 | |||
547 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE | ||
548 | LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR | ||
549 | OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, | ||
550 | EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
551 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE | ||
552 | ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. | ||
553 | SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY | ||
554 | SERVICING, REPAIR OR CORRECTION. | ||
555 | |||
556 | 16. Limitation of Liability. | ||
557 | |||
558 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY | ||
559 | COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS | ||
560 | PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, | ||
561 | INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE | ||
562 | THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED | ||
563 | INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE | ||
564 | PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER | ||
565 | PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | ||
566 | |||
567 | 17. Interpretation of Sections 15 and 16. | ||
568 | |||
569 | If the disclaimer of warranty and limitation of liability provided above cannot | ||
570 | be given local legal effect according to their terms, reviewing courts shall | ||
571 | apply local law that most closely approximates an absolute waiver of all civil | ||
572 | liability in connection with the Program, unless a warranty or assumption of | ||
573 | liability accompanies a copy of the Program in return for a fee. | ||
574 | |||
575 | END OF TERMS AND CONDITIONS | ||
576 | |||
577 | How to Apply These Terms to Your New Programs | ||
578 | |||
579 | If you develop a new program, and you want it to be of the greatest possible | ||
580 | use to the public, the best way to achieve this is to make it free software | ||
581 | which everyone can redistribute and change under these terms. | ||
582 | |||
583 | To do so, attach the following notices to the program. It is safest to attach | ||
584 | them to the start of each source file to most effectively state the exclusion | ||
585 | of warranty; and each file should have at least the "copyright" line and a | ||
586 | pointer to where the full notice is found. | ||
587 | |||
588 | <one line to give the program's name and a brief idea of what it does.> | ||
589 | Copyright (C) <year> <name of author> | ||
590 | |||
591 | This program is free software: you can redistribute it and/or modify it | ||
592 | under the terms of the GNU Affero General Public License as published by | ||
593 | the Free Software Foundation, either version 3 of the License, or (at | ||
594 | your option) any later version. | ||
595 | |||
596 | This program is distributed in the hope that it will be useful, but | ||
597 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
598 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public | ||
599 | License for more details. | ||
600 | |||
601 | You should have received a copy of the GNU Affero General Public License | ||
602 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
603 | |||
604 | Also add information on how to contact you by electronic and paper mail. | ||
605 | |||
606 | If your software can interact with users remotely through a computer network, | ||
607 | you should also make sure that it provides a way for users to get its source. | ||
608 | For example, if your program is a web application, its interface could display | ||
609 | a "Source" link that leads users to an archive of the code. There are many | ||
610 | ways you could offer source, and different solutions will be better for | ||
611 | different programs; see section 13 for the specific requirements. | ||
612 | |||
613 | You should also get your employer (if you work as a programmer) or school, if | ||
614 | any, to sign a "copyright disclaimer" for the program, if necessary. For more | ||
615 | information on this, and how to apply and follow the GNU AGPL, see | ||
616 | <http://www.gnu.org/licenses/>. | ||
@@ -33,6 +33,7 @@ packages are accessible through `GOPATH`. To install the dependencies: | |||
33 | ```bash | 33 | ```bash |
34 | $ go get -u golang.org/x/crypto/... | 34 | $ go get -u golang.org/x/crypto/... |
35 | $ go get -u golang.org/x/text/... | 35 | $ go get -u golang.org/x/text/... |
36 | $ go get -u github.com/miekg/dns/... | ||
36 | $ go get -u github.com/bfix/gospel/... | 37 | $ go get -u github.com/bfix/gospel/... |
37 | ``` | 38 | ``` |
38 | 39 | ||
diff --git a/src/gnunet/config/config.go b/src/gnunet/config/config.go index 1a53941..eaadd98 100644 --- a/src/gnunet/config/config.go +++ b/src/gnunet/config/config.go | |||
@@ -7,9 +7,10 @@ import ( | |||
7 | "regexp" | 7 | "regexp" |
8 | "strings" | 8 | "strings" |
9 | 9 | ||
10 | "gnunet/util" | ||
11 | |||
10 | "github.com/bfix/gospel/crypto/ed25519" | 12 | "github.com/bfix/gospel/crypto/ed25519" |
11 | "github.com/bfix/gospel/logger" | 13 | "github.com/bfix/gospel/logger" |
12 | "gnunet/util" | ||
13 | ) | 14 | ) |
14 | 15 | ||
15 | /////////////////////////////////////////////////////////////////////// | 16 | /////////////////////////////////////////////////////////////////////// |
@@ -64,6 +65,7 @@ type Config struct { | |||
64 | } | 65 | } |
65 | 66 | ||
66 | var ( | 67 | var ( |
68 | // Cfg is the global configuration | ||
67 | Cfg *Config | 69 | Cfg *Config |
68 | ) | 70 | ) |
69 | 71 | ||
@@ -88,6 +90,8 @@ var ( | |||
88 | rx = regexp.MustCompile("\\$\\{([^\\}]*)\\}") | 90 | rx = regexp.MustCompile("\\$\\{([^\\}]*)\\}") |
89 | ) | 91 | ) |
90 | 92 | ||
93 | // substString is a helper function to substitute environment variables | ||
94 | // with actual values. | ||
91 | func substString(s string, env map[string]string) string { | 95 | func substString(s string, env map[string]string) string { |
92 | matches := rx.FindAllStringSubmatch(s, -1) | 96 | matches := rx.FindAllStringSubmatch(s, -1) |
93 | for _, m := range matches { | 97 | for _, m := range matches { |
@@ -102,7 +106,8 @@ func substString(s string, env map[string]string) string { | |||
102 | return s | 106 | return s |
103 | } | 107 | } |
104 | 108 | ||
105 | // applySubstitutions | 109 | // applySubstitutions traverses the configuration data structure |
110 | // and applies string substitutions to all string values. | ||
106 | func applySubstitutions(x interface{}, env map[string]string) { | 111 | func applySubstitutions(x interface{}, env map[string]string) { |
107 | 112 | ||
108 | var process func(v reflect.Value) | 113 | var process func(v reflect.Value) |
@@ -140,10 +145,11 @@ func applySubstitutions(x interface{}, env map[string]string) { | |||
140 | } | 145 | } |
141 | } | 146 | } |
142 | } | 147 | } |
143 | 148 | // start processing at the top-level structure | |
144 | v := reflect.ValueOf(x) | 149 | v := reflect.ValueOf(x) |
145 | switch v.Kind() { | 150 | switch v.Kind() { |
146 | case reflect.Ptr: | 151 | case reflect.Ptr: |
152 | // indirect top-level | ||
147 | e := v.Elem() | 153 | e := v.Elem() |
148 | if e.IsValid() { | 154 | if e.IsValid() { |
149 | process(e) | 155 | process(e) |
@@ -151,6 +157,7 @@ func applySubstitutions(x interface{}, env map[string]string) { | |||
151 | logger.Printf(logger.ERROR, "[config] 'nil' pointer encountered") | 157 | logger.Printf(logger.ERROR, "[config] 'nil' pointer encountered") |
152 | } | 158 | } |
153 | case reflect.Struct: | 159 | case reflect.Struct: |
160 | // direct top-level | ||
154 | process(v) | 161 | process(v) |
155 | } | 162 | } |
156 | } | 163 | } |
diff --git a/src/gnunet/core/peer.go b/src/gnunet/core/peer.go index ac2d980..d0b3a4c 100644 --- a/src/gnunet/core/peer.go +++ b/src/gnunet/core/peer.go | |||
@@ -3,30 +3,25 @@ package core | |||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | 5 | ||
6 | "github.com/bfix/gospel/crypto/ed25519" | ||
7 | "gnunet/message" | 6 | "gnunet/message" |
8 | "gnunet/util" | 7 | "gnunet/util" |
9 | ) | ||
10 | 8 | ||
11 | /* | 9 | "github.com/bfix/gospel/crypto/ed25519" |
12 | type Peer interface { | 10 | ) |
13 | GetID() []byte | ||
14 | GetIDString() string | ||
15 | GetAddressList() []*util.Address | ||
16 | Sign(msg []byte) ([]byte, error) | ||
17 | Verify(msg, sig []byte) bool | ||
18 | } | ||
19 | */ | ||
20 | 11 | ||
12 | // Peer represents a node in the GNUnet P2P network. | ||
21 | type Peer struct { | 13 | type Peer struct { |
22 | pub *ed25519.PublicKey | 14 | prv *ed25519.PrivateKey // node private key (long-term signing key) |
23 | idString string | 15 | pub *ed25519.PublicKey // node public key (=identifier) |
24 | addrList []*util.Address | 16 | idString string // node identifier as string |
25 | prv *ed25519.PrivateKey // long-term signing key | 17 | addrList []*util.Address // list of addresses associated with node |
26 | ephPrv *ed25519.PrivateKey // ephemeral signing key | 18 | ephPrv *ed25519.PrivateKey // ephemeral signing key |
27 | ephMsg *message.EphemeralKeyMsg // ephemeral signing key message | 19 | ephMsg *message.EphemeralKeyMsg // ephemeral signing key message |
28 | } | 20 | } |
29 | 21 | ||
22 | // NewPeer instantiates a new peer object from given data. If a local peer | ||
23 | // is created, the data is the seed for generating the private key of the node; | ||
24 | // for a remote peer the data is the binary representation of its public key. | ||
30 | func NewPeer(data []byte, local bool) (p *Peer, err error) { | 25 | func NewPeer(data []byte, local bool) (p *Peer, err error) { |
31 | p = new(Peer) | 26 | p = new(Peer) |
32 | if local { | 27 | if local { |
@@ -45,42 +40,52 @@ func NewPeer(data []byte, local bool) (p *Peer, err error) { | |||
45 | return | 40 | return |
46 | } | 41 | } |
47 | 42 | ||
43 | // EphKeyMsg returns a new initialized message to negotiate session keys. | ||
48 | func (p *Peer) EphKeyMsg() *message.EphemeralKeyMsg { | 44 | func (p *Peer) EphKeyMsg() *message.EphemeralKeyMsg { |
49 | return p.ephMsg | 45 | return p.ephMsg |
50 | } | 46 | } |
51 | 47 | ||
48 | // SetEphKeyMsg saves a template for new key negotiation messages. | ||
52 | func (p *Peer) SetEphKeyMsg(msg *message.EphemeralKeyMsg) { | 49 | func (p *Peer) SetEphKeyMsg(msg *message.EphemeralKeyMsg) { |
53 | p.ephMsg = msg | 50 | p.ephMsg = msg |
54 | } | 51 | } |
55 | 52 | ||
53 | // EphPrvKey returns the current ephemeral private key. | ||
56 | func (p *Peer) EphPrvKey() *ed25519.PrivateKey { | 54 | func (p *Peer) EphPrvKey() *ed25519.PrivateKey { |
57 | return p.ephPrv | 55 | return p.ephPrv |
58 | } | 56 | } |
59 | 57 | ||
58 | // PrvKey return the private key of the node. | ||
60 | func (p *Peer) PrvKey() *ed25519.PrivateKey { | 59 | func (p *Peer) PrvKey() *ed25519.PrivateKey { |
61 | return p.prv | 60 | return p.prv |
62 | } | 61 | } |
63 | 62 | ||
63 | // PubKey return the public key of the node. | ||
64 | func (p *Peer) PubKey() *ed25519.PublicKey { | 64 | func (p *Peer) PubKey() *ed25519.PublicKey { |
65 | return p.pub | 65 | return p.pub |
66 | } | 66 | } |
67 | 67 | ||
68 | // GetID returns the node ID (public key) in binary format | ||
68 | func (p *Peer) GetID() []byte { | 69 | func (p *Peer) GetID() []byte { |
69 | return p.pub.Bytes() | 70 | return p.pub.Bytes() |
70 | } | 71 | } |
71 | 72 | ||
73 | // GetIDString returns the string representation of the public key of the node. | ||
72 | func (p *Peer) GetIDString() string { | 74 | func (p *Peer) GetIDString() string { |
73 | return p.idString | 75 | return p.idString |
74 | } | 76 | } |
75 | 77 | ||
78 | // GetAddressList returns a list of addresses associated with this peer. | ||
76 | func (p *Peer) GetAddressList() []*util.Address { | 79 | func (p *Peer) GetAddressList() []*util.Address { |
77 | return p.addrList | 80 | return p.addrList |
78 | } | 81 | } |
79 | 82 | ||
83 | // AddAddress adds a new address for a node. | ||
80 | func (p *Peer) AddAddress(a *util.Address) { | 84 | func (p *Peer) AddAddress(a *util.Address) { |
81 | p.addrList = append(p.addrList, a) | 85 | p.addrList = append(p.addrList, a) |
82 | } | 86 | } |
83 | 87 | ||
88 | // Sign a message with the (long-term) private key. | ||
84 | func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error) { | 89 | func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error) { |
85 | if p.prv == nil { | 90 | if p.prv == nil { |
86 | return nil, fmt.Errorf("No private key") | 91 | return nil, fmt.Errorf("No private key") |
@@ -88,6 +93,7 @@ func (p *Peer) Sign(msg []byte) (*ed25519.EdSignature, error) { | |||
88 | return p.prv.EdSign(msg) | 93 | return p.prv.EdSign(msg) |
89 | } | 94 | } |
90 | 95 | ||
96 | // Verify a message signature with the public key of a peer. | ||
91 | func (p *Peer) Verify(msg []byte, sig *ed25519.EdSignature) (bool, error) { | 97 | func (p *Peer) Verify(msg []byte, sig *ed25519.EdSignature) (bool, error) { |
92 | return p.pub.EdVerify(msg, sig) | 98 | return p.pub.EdVerify(msg, sig) |
93 | } | 99 | } |
diff --git a/src/gnunet/crypto/gns.go b/src/gnunet/crypto/gns.go new file mode 100644 index 0000000..c6a8cd6 --- /dev/null +++ b/src/gnunet/crypto/gns.go | |||
@@ -0,0 +1,35 @@ | |||
1 | package crypto | ||
2 | |||
3 | import ( | ||
4 | "crypto/sha256" | ||
5 | "crypto/sha512" | ||
6 | |||
7 | "github.com/bfix/gospel/crypto/ed25519" | ||
8 | "golang.org/x/crypto/hkdf" | ||
9 | ) | ||
10 | |||
11 | // DeriveBlockKey returns a symmetric key and initialization vector to decipher a GNS block. | ||
12 | func DeriveBlockKey(label string, pub *ed25519.PublicKey) (iv *SymmetricIV, skey *SymmetricKey) { | ||
13 | // generate symmetric key | ||
14 | prk := hkdf.Extract(sha512.New, pub.Bytes(), []byte("gns-aes-ctx-key")) | ||
15 | rdr := hkdf.Expand(sha256.New, prk, []byte(label)) | ||
16 | skey = NewSymmetricKey() | ||
17 | rdr.Read(skey.AESKey) | ||
18 | rdr.Read(skey.TwofishKey) | ||
19 | |||
20 | // generate initialization vector | ||
21 | prk = hkdf.Extract(sha512.New, pub.Bytes(), []byte("gns-aes-ctx-iv")) | ||
22 | rdr = hkdf.Expand(sha256.New, prk, []byte(label)) | ||
23 | iv = NewSymmetricIV() | ||
24 | rdr.Read(iv.AESIv) | ||
25 | rdr.Read(iv.TwofishIv) | ||
26 | return | ||
27 | } | ||
28 | |||
29 | // DecryptBlock for a given zone and label. | ||
30 | func DecryptBlock(data []byte, zoneKey *ed25519.PublicKey, label string) (out []byte, err error) { | ||
31 | // derive key material for decryption | ||
32 | iv, skey := DeriveBlockKey(label, zoneKey) | ||
33 | // perform decryption | ||
34 | return SymmetricDecrypt(data, skey, iv) | ||
35 | } | ||
diff --git a/src/gnunet/crypto/gns_test.go b/src/gnunet/crypto/gns_test.go new file mode 100644 index 0000000..7f3cdb8 --- /dev/null +++ b/src/gnunet/crypto/gns_test.go | |||
@@ -0,0 +1,150 @@ | |||
1 | package crypto | ||
2 | |||
3 | import ( | ||
4 | "bytes" | ||
5 | "encoding/hex" | ||
6 | "testing" | ||
7 | |||
8 | "github.com/bfix/gospel/crypto/ed25519" | ||
9 | ) | ||
10 | |||
11 | var ( | ||
12 | PUB = []byte{ | ||
13 | 0x93, 0x34, 0x71, 0xF6, 0x99, 0x19, 0x0C, 0x62, | ||
14 | 0x85, 0xC7, 0x9B, 0x83, 0x9D, 0xCA, 0x83, 0x91, | ||
15 | 0x38, 0xFA, 0x87, 0xFB, 0xB8, 0xD4, 0xF6, 0xF0, | ||
16 | 0xF0, 0x4B, 0x7F, 0x0A, 0x48, 0xBF, 0x95, 0xF7, | ||
17 | } | ||
18 | LABEL = "home" | ||
19 | ) | ||
20 | |||
21 | func TestDeriveBlockKey(t *testing.T) { | ||
22 | var ( | ||
23 | SKEY = []byte{ | ||
24 | 0x1D, 0x86, 0x8E, 0xF7, 0x30, 0x96, 0x3B, 0x39, | ||
25 | 0x66, 0xE6, 0x49, 0xD8, 0xF1, 0x13, 0x18, 0x39, | ||
26 | 0x8A, 0x7A, 0xB0, 0xF3, 0xDC, 0xF6, 0xE7, 0x2A, | ||
27 | 0xF6, 0x65, 0xDE, 0x86, 0x47, 0x7B, 0x20, 0x1B, | ||
28 | |||
29 | 0x21, 0xA6, 0xFA, 0x55, 0x7C, 0x29, 0xF5, 0x94, | ||
30 | 0x8E, 0x9A, 0x80, 0xB0, 0xB6, 0xD5, 0x4D, 0x38, | ||
31 | 0x0E, 0x6A, 0x0F, 0x42, 0x4B, 0x27, 0xBB, 0x6A, | ||
32 | 0x1E, 0xD1, 0x33, 0x08, 0xD6, 0x2E, 0x21, 0x8C, | ||
33 | } | ||
34 | IV = []byte{ | ||
35 | 0xAC, 0x18, 0x03, 0xB7, 0x8B, 0x1E, 0x09, 0xA9, | ||
36 | 0xD0, 0x20, 0x47, 0x2B, 0x1B, 0x23, 0xE8, 0x24, | ||
37 | |||
38 | 0xC9, 0x23, 0x9E, 0x61, 0x3A, 0x8D, 0x95, 0xA9, | ||
39 | 0x3F, 0x6C, 0x1C, 0xC8, 0xCB, 0xD1, 0xBD, 0x6B, | ||
40 | } | ||
41 | ) | ||
42 | |||
43 | iv, skey := DeriveBlockKey(LABEL, ed25519.NewPublicKeyFromBytes(PUB)) | ||
44 | |||
45 | if bytes.Compare(IV[:16], iv.AESIv) != 0 { | ||
46 | t.Logf("AES_IV(computed) = %s\n", hex.EncodeToString(iv.AESIv)) | ||
47 | t.Logf("AES_IV(expected) = %s\n", hex.EncodeToString(IV[:16])) | ||
48 | t.Fatal("AES IV mismatch") | ||
49 | } | ||
50 | if bytes.Compare(IV[16:], iv.TwofishIv) != 0 { | ||
51 | t.Logf("Twofish_IV(computed) = %s\n", hex.EncodeToString(iv.TwofishIv)) | ||
52 | t.Logf("Twofish_IV(expected) = %s\n", hex.EncodeToString(IV[16:])) | ||
53 | t.Fatal("Twofish IV mismatch") | ||
54 | } | ||
55 | |||
56 | if bytes.Compare(SKEY[:32], skey.AESKey) != 0 { | ||
57 | t.Logf("AES_KEY(computed) = %s\n", hex.EncodeToString(skey.AESKey)) | ||
58 | t.Logf("AES_KEY(expected) = %s\n", hex.EncodeToString(SKEY[:32])) | ||
59 | t.Fatal("AES KEY mismatch") | ||
60 | } | ||
61 | if bytes.Compare(SKEY[32:], skey.TwofishKey) != 0 { | ||
62 | t.Logf("Twofish_KEY(computed) = %s\n", hex.EncodeToString(skey.TwofishKey)) | ||
63 | t.Logf("Twofish_KEY(expected) = %s\n", hex.EncodeToString(SKEY[32:])) | ||
64 | t.Fatal("Twofish KEY mismatch") | ||
65 | } | ||
66 | } | ||
67 | |||
68 | func TestDecryptBlock(t *testing.T) { | ||
69 | var ( | ||
70 | DATA = []byte{ | ||
71 | 0xAC, 0xA5, 0x3C, 0x55, 0x63, 0x21, 0x31, 0x1F, | ||
72 | 0x11, 0x6E, 0xEF, 0x48, 0xED, 0x53, 0x46, 0x31, | ||
73 | 0x7C, 0x50, 0xFB, 0x6B, 0xA6, 0xC8, 0x6C, 0x46, | ||
74 | 0x1E, 0xE3, 0xCA, 0x45, 0xCD, 0x5B, 0xD6, 0x86, | ||
75 | 0x42, 0x87, 0xEF, 0x18, 0xCE, 0x8E, 0x83, 0x21, | ||
76 | 0x04, 0xCB, 0xCF, 0x40, 0x7E, 0x0F, 0x51, 0x54, | ||
77 | 0xE2, 0x3C, 0xDE, 0xE9, 0x22, 0x00, 0xFF, 0x40, | ||
78 | 0xBB, 0x53, 0xE3, 0x69, 0x99, 0x92, 0x47, 0x97, | ||
79 | 0xF0, 0x4E, 0x3B, 0x70, | ||
80 | } | ||
81 | OUT = []byte{ | ||
82 | 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0xAD, 0x0E, | ||
83 | 0x60, 0x28, 0xFE, 0x80, 0x00, 0x00, 0x00, 0x10, | ||
84 | 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, | ||
85 | 0x0A, 0x68, 0x6F, 0x69, 0x2D, 0x70, 0x6F, 0x6C, | ||
86 | 0x6C, 0x6F, 0x69, 0x03, 0x6F, 0x72, 0x67, 0x00, | ||
87 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
88 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||
90 | 0x00, 0x00, 0x00, 0x00, | ||
91 | } | ||
92 | ) | ||
93 | |||
94 | out, err := DecryptBlock(DATA, ed25519.NewPublicKeyFromBytes(PUB), LABEL) | ||
95 | if err != nil { | ||
96 | t.Fatal(err) | ||
97 | } | ||
98 | if bytes.Compare(out, OUT) != 0 { | ||
99 | t.Logf("Decrypt(computed) = %s\n", hex.EncodeToString(out)) | ||
100 | t.Logf("Decrypt(expected) = %s\n", hex.EncodeToString(OUT)) | ||
101 | t.Fatal("Decryptions failed") | ||
102 | } | ||
103 | } | ||
104 | |||
105 | func TestVerifyBlock(t *testing.T) { | ||
106 | var ( | ||
107 | SIGNED = []byte{ | ||
108 | 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x0f, | ||
109 | 0x00, 0x05, 0xad, 0x0e, 0x60, 0x28, 0xfe, 0x80, | ||
110 | 0xac, 0xa5, 0x3c, 0x55, 0x63, 0x21, 0x31, 0x1f, | ||
111 | 0x11, 0x6e, 0xef, 0x48, 0xed, 0x53, 0x46, 0x31, | ||
112 | 0x7c, 0x50, 0xfb, 0x6b, 0xa6, 0xc8, 0x6c, 0x46, | ||
113 | 0x1e, 0xe3, 0xca, 0x45, 0xcd, 0x5b, 0xd6, 0x86, | ||
114 | 0x42, 0x87, 0xef, 0x18, 0xce, 0x8e, 0x83, 0x21, | ||
115 | 0x04, 0xcb, 0xcf, 0x40, 0x7e, 0x0f, 0x51, 0x54, | ||
116 | 0xe2, 0x3c, 0xde, 0xe9, 0x22, 0x00, 0xff, 0x40, | ||
117 | 0xbb, 0x53, 0xe3, 0x69, 0x99, 0x92, 0x47, 0x97, | ||
118 | 0xf0, 0x4e, 0x3b, 0x70, | ||
119 | } | ||
120 | SIG = []byte{ | ||
121 | 0x09, 0xc9, 0x6a, 0xda, 0x69, 0xce, 0x7c, 0x91, | ||
122 | 0xbd, 0xa4, 0x59, 0xdc, 0xc9, 0x76, 0xf4, 0x6c, | ||
123 | 0x62, 0xb7, 0x79, 0x3f, 0x94, 0xb2, 0xf6, 0xf0, | ||
124 | 0x90, 0x17, 0x4e, 0x2f, 0x68, 0x49, 0xf8, 0xcc, | ||
125 | |||
126 | 0x0b, 0x77, 0x32, 0x32, 0x28, 0x77, 0x2d, 0x2a, | ||
127 | 0x31, 0x31, 0xc1, 0x2c, 0x44, 0x18, 0xf2, 0x5f, | ||
128 | 0x1a, 0xe9, 0x8b, 0x2e, 0x65, 0xca, 0x1d, 0xe8, | ||
129 | 0x22, 0x82, 0x6a, 0x06, 0xe0, 0x6a, 0x5a, 0xe5, | ||
130 | } | ||
131 | PUB = []byte{ | ||
132 | 0x26, 0x84, 0x1b, 0x24, 0x35, 0xa4, 0x63, 0xe9, | ||
133 | 0xf0, 0x48, 0xae, 0x3e, 0xf7, 0xe8, 0x1b, 0xca, | ||
134 | 0x55, 0x9f, 0x4c, 0x1e, 0x16, 0x18, 0xa6, 0xd3, | ||
135 | 0x5b, 0x91, 0x0d, 0x54, 0x31, 0x6e, 0xbf, 0x97, | ||
136 | } | ||
137 | ) | ||
138 | sig, err := ed25519.NewEcSignatureFromBytes(SIG) | ||
139 | if err != nil { | ||
140 | t.Fatal(err) | ||
141 | } | ||
142 | dkey := ed25519.NewPublicKeyFromBytes(PUB) | ||
143 | ok, err := dkey.EcVerify(SIGNED, sig) | ||
144 | if err != nil { | ||
145 | t.Fatal(err) | ||
146 | } | ||
147 | if !ok { | ||
148 | t.Fatal("EcDSA verify failed") | ||
149 | } | ||
150 | } | ||
diff --git a/src/gnunet/crypto/hash.go b/src/gnunet/crypto/hash.go index 87e3941..0fe7c7e 100644 --- a/src/gnunet/crypto/hash.go +++ b/src/gnunet/crypto/hash.go | |||
@@ -6,16 +6,19 @@ import ( | |||
6 | "gnunet/util" | 6 | "gnunet/util" |
7 | ) | 7 | ) |
8 | 8 | ||
9 | // HashCode is the result of a 512-bit hash function (SHA-512) | ||
9 | type HashCode struct { | 10 | type HashCode struct { |
10 | Bits []byte `size:"64"` | 11 | Bits []byte `size:"64"` |
11 | } | 12 | } |
12 | 13 | ||
14 | // NewHashCode creates a new, uninitalized hash value | ||
13 | func NewHashCode() *HashCode { | 15 | func NewHashCode() *HashCode { |
14 | return &HashCode{ | 16 | return &HashCode{ |
15 | Bits: make([]byte, 64), | 17 | Bits: make([]byte, 64), |
16 | } | 18 | } |
17 | } | 19 | } |
18 | 20 | ||
21 | // Hash returns the SHA-512 hash value of a given blob | ||
19 | func Hash(data []byte) *HashCode { | 22 | func Hash(data []byte) *HashCode { |
20 | val := sha512.Sum512(data) | 23 | val := sha512.Sum512(data) |
21 | return &HashCode{ | 24 | return &HashCode{ |
diff --git a/src/gnunet/crypto/key_derivation.go b/src/gnunet/crypto/key_derivation.go index 575f511..976db2a 100644 --- a/src/gnunet/crypto/key_derivation.go +++ b/src/gnunet/crypto/key_derivation.go | |||
@@ -9,6 +9,7 @@ import ( | |||
9 | "golang.org/x/crypto/hkdf" | 9 | "golang.org/x/crypto/hkdf" |
10 | ) | 10 | ) |
11 | 11 | ||
12 | // Curve parameters | ||
12 | var ( | 13 | var ( |
13 | ED25519_N = ed25519.GetCurve().N | 14 | ED25519_N = ed25519.GetCurve().N |
14 | ) | 15 | ) |
diff --git a/src/gnunet/crypto/key_exchange.go b/src/gnunet/crypto/key_exchange.go index 0efa441..1403249 100644 --- a/src/gnunet/crypto/key_exchange.go +++ b/src/gnunet/crypto/key_exchange.go | |||
@@ -4,8 +4,8 @@ import ( | |||
4 | "github.com/bfix/gospel/crypto/ed25519" | 4 | "github.com/bfix/gospel/crypto/ed25519" |
5 | ) | 5 | ) |
6 | 6 | ||
7 | // SharedSecret computes a 64 byte shared secret | 7 | // SharedSecret computes a 64 byte shared secret between (prvA,pubB) |
8 | // between (prvA,pubB) and (prvB,pubA). | 8 | // and (prvB,pubA) by a Diffie-Hellman-like scheme. |
9 | func SharedSecret(prv *ed25519.PrivateKey, pub *ed25519.PublicKey) *HashCode { | 9 | func SharedSecret(prv *ed25519.PrivateKey, pub *ed25519.PublicKey) *HashCode { |
10 | ss := pub.Mult(prv.D).Q.X().Bytes() | 10 | ss := pub.Mult(prv.D).Q.X().Bytes() |
11 | return Hash(ss) | 11 | return Hash(ss) |
diff --git a/src/gnunet/crypto/signature.go b/src/gnunet/crypto/signature.go index 9a69b56..ba8e535 100644 --- a/src/gnunet/crypto/signature.go +++ b/src/gnunet/crypto/signature.go | |||
@@ -1,5 +1,6 @@ | |||
1 | package crypto | 1 | package crypto |
2 | 2 | ||
3 | // SignaturePurpose is the GNUnet data structure used as header for signed data. | ||
3 | type SignaturePurpose struct { | 4 | type SignaturePurpose struct { |
4 | Size uint32 `order:"big"` // How many bytes are signed? | 5 | Size uint32 `order:"big"` // How many bytes are signed? |
5 | Purpose uint32 `order:"big"` // Signature purpose | 6 | Purpose uint32 `order:"big"` // Signature purpose |
diff --git a/src/gnunet/crypto/symmetric.go b/src/gnunet/crypto/symmetric.go index 82116a4..5607d3a 100644 --- a/src/gnunet/crypto/symmetric.go +++ b/src/gnunet/crypto/symmetric.go | |||
@@ -8,11 +8,17 @@ import ( | |||
8 | "golang.org/x/crypto/twofish" | 8 | "golang.org/x/crypto/twofish" |
9 | ) | 9 | ) |
10 | 10 | ||
11 | // Symmetric encryption in GNUnet uses a two-layer scheme: | ||
12 | // * Encryption: OUT = twofish_cfb(aes_cfb(IN)) | ||
13 | // * Decryption: OUT = aes_cfb(twofish_cfb(IN)) | ||
14 | |||
15 | // SymmetricKey is a key for the GNUnet-specific two-layer encryption scheme. | ||
11 | type SymmetricKey struct { | 16 | type SymmetricKey struct { |
12 | AESKey []byte `size:"32"` | 17 | AESKey []byte `size:"32"` // key for AES-CFB |
13 | TwofishKey []byte `size:"32"` | 18 | TwofishKey []byte `size:"32"` // key for Twofish-CFB |
14 | } | 19 | } |
15 | 20 | ||
21 | // NewSymmetricKey generates a new (random) symmetric key. | ||
16 | func NewSymmetricKey() *SymmetricKey { | 22 | func NewSymmetricKey() *SymmetricKey { |
17 | skey := &SymmetricKey{ | 23 | skey := &SymmetricKey{ |
18 | AESKey: make([]byte, 32), | 24 | AESKey: make([]byte, 32), |
@@ -23,11 +29,14 @@ func NewSymmetricKey() *SymmetricKey { | |||
23 | return skey | 29 | return skey |
24 | } | 30 | } |
25 | 31 | ||
32 | // SymmetricIV is an initialization vector for the GNUnet-specific two-layer | ||
33 | // encryption scheme. | ||
26 | type SymmetricIV struct { | 34 | type SymmetricIV struct { |
27 | AESIv []byte `size:"16"` | 35 | AESIv []byte `size:"16"` // IV for AES-CFB |
28 | TwofishIv []byte `size:"16"` | 36 | TwofishIv []byte `size:"16"` // IV for Twofish-CFB |
29 | } | 37 | } |
30 | 38 | ||
39 | // NewSymmetricIV generates a new (random) initialization vector. | ||
31 | func NewSymmetricIV() *SymmetricIV { | 40 | func NewSymmetricIV() *SymmetricIV { |
32 | iv := &SymmetricIV{ | 41 | iv := &SymmetricIV{ |
33 | AESIv: make([]byte, 16), | 42 | AESIv: make([]byte, 16), |
@@ -38,6 +47,7 @@ func NewSymmetricIV() *SymmetricIV { | |||
38 | return iv | 47 | return iv |
39 | } | 48 | } |
40 | 49 | ||
50 | // SymmetricDecrypt decrypts the data with given key and initialization vector. | ||
41 | func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) { | 51 | func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) { |
42 | // Decrypt with Twofish CFB stream cipher | 52 | // Decrypt with Twofish CFB stream cipher |
43 | tf, err := twofish.NewCipher(skey.TwofishKey) | 53 | tf, err := twofish.NewCipher(skey.TwofishKey) |
@@ -58,6 +68,7 @@ func SymmetricDecrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, | |||
58 | return out, nil | 68 | return out, nil |
59 | } | 69 | } |
60 | 70 | ||
71 | // SymmetricEncrypt encrypts the data with given key and initialization vector. | ||
61 | func SymmetricEncrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) { | 72 | func SymmetricEncrypt(data []byte, skey *SymmetricKey, iv *SymmetricIV) ([]byte, error) { |
62 | // Encrypt with AES CFB stream cipher | 73 | // Encrypt with AES CFB stream cipher |
63 | aes, err := aes.NewCipher(skey.AESKey) | 74 | aes, err := aes.NewCipher(skey.AESKey) |
diff --git a/src/gnunet/enums/dht.go b/src/gnunet/enums/dht.go index 87c36a3..8f004d7 100644 --- a/src/gnunet/enums/dht.go +++ b/src/gnunet/enums/dht.go | |||
@@ -1,5 +1,6 @@ | |||
1 | package enums | 1 | package enums |
2 | 2 | ||
3 | // DHT flags and settings | ||
3 | var ( | 4 | var ( |
4 | DHT_RO_NONE = 0 // Default. Do nothing special. | 5 | DHT_RO_NONE = 0 // Default. Do nothing special. |
5 | DHT_RO_DEMULTIPLEX_EVERYWHERE = 1 // Each peer along the way should look at 'enc' | 6 | DHT_RO_DEMULTIPLEX_EVERYWHERE = 1 // Each peer along the way should look at 'enc' |
@@ -10,3 +11,25 @@ var ( | |||
10 | 11 | ||
11 | DHT_GNS_REPLICATION_LEVEL = 10 | 12 | DHT_GNS_REPLICATION_LEVEL = 10 |
12 | ) | 13 | ) |
14 | |||
15 | // DHT block types | ||
16 | var ( | ||
17 | BLOCK_TYPE_ANY = 0 // Any type of block, used as a wildcard when searching. | ||
18 | BLOCK_TYPE_FS_DBLOCK = 1 // Data block (leaf) in the CHK tree. | ||
19 | BLOCK_TYPE_FS_IBLOCK = 2 // Inner block in the CHK tree. | ||
20 | BLOCK_TYPE_FS_KBLOCK = 3 // Legacy type, no longer in use. | ||
21 | BLOCK_TYPE_FS_SBLOCK = 4 // Legacy type, no longer in use. | ||
22 | BLOCK_TYPE_FS_NBLOCK = 5 // Legacy type, no longer in use. | ||
23 | BLOCK_TYPE_FS_ONDEMAND = 6 // Type of a block representing a block to be encoded on demand from disk. | ||
24 | BLOCK_TYPE_DHT_HELLO = 7 // Type of a block that contains a HELLO for a peer | ||
25 | BLOCK_TYPE_TEST = 8 // Block for testing. | ||
26 | BLOCK_TYPE_FS_UBLOCK = 9 // Type of a block representing any type of search result (universal). | ||
27 | BLOCK_TYPE_DNS = 10 // Block for storing DNS exit service advertisements. | ||
28 | BLOCK_TYPE_GNS_NAMERECORD = 11 // Block for storing record data | ||
29 | BLOCK_TYPE_REVOCATION = 12 // Block type for a revocation message by which a key is revoked. | ||
30 | |||
31 | BLOCK_TYPE_REGEX = 22 // Block to store a cadet regex state | ||
32 | BLOCK_TYPE_REGEX_ACCEPT = 23 // Block to store a cadet regex accepting state | ||
33 | BLOCK_TYPE_SET_TEST = 24 // Block for testing set/consensus. | ||
34 | BLOCK_TYPE_CONSENSUS_ELEMENT = 25 // Block type for consensus elements. | ||
35 | ) | ||
diff --git a/src/gnunet/enums/gns.go b/src/gnunet/enums/gns.go index 2de5048..d5b1f7a 100644 --- a/src/gnunet/enums/gns.go +++ b/src/gnunet/enums/gns.go | |||
@@ -1,5 +1,6 @@ | |||
1 | package enums | 1 | package enums |
2 | 2 | ||
3 | // GNS constants | ||
3 | var ( | 4 | var ( |
4 | GNS_MAX_BLOCK_SIZE = (63 * 1024) // Maximum size of a value that can be stored in a GNS block. | 5 | GNS_MAX_BLOCK_SIZE = (63 * 1024) // Maximum size of a value that can be stored in a GNS block. |
5 | 6 | ||
diff --git a/src/gnunet/message/message.go b/src/gnunet/message/message.go index 6b49a55..e792ae8 100644 --- a/src/gnunet/message/message.go +++ b/src/gnunet/message/message.go | |||
@@ -6,27 +6,35 @@ import ( | |||
6 | "github.com/bfix/gospel/data" | 6 | "github.com/bfix/gospel/data" |
7 | ) | 7 | ) |
8 | 8 | ||
9 | // Error codes | ||
9 | var ( | 10 | var ( |
10 | ErrMsgHeaderTooSmall = errors.New("Message header too small") | 11 | ErrMsgHeaderTooSmall = errors.New("Message header too small") |
11 | ) | 12 | ) |
12 | 13 | ||
14 | // Message is an interface for all GNUnet-specific messages. | ||
13 | type Message interface { | 15 | type Message interface { |
14 | Header() *MessageHeader | 16 | Header() *MessageHeader |
15 | } | 17 | } |
16 | 18 | ||
19 | // MessageHeader encapsulates the common part of all GNUnet messages (at the | ||
20 | // beginning of the data). | ||
17 | type MessageHeader struct { | 21 | type MessageHeader struct { |
18 | MsgSize uint16 `order:"big"` | 22 | MsgSize uint16 `order:"big"` |
19 | MsgType uint16 `order:"big"` | 23 | MsgType uint16 `order:"big"` |
20 | } | 24 | } |
21 | 25 | ||
26 | // Size returns the total size of the message (header + body) | ||
22 | func (mh *MessageHeader) Size() uint16 { | 27 | func (mh *MessageHeader) Size() uint16 { |
23 | return mh.MsgSize | 28 | return mh.MsgSize |
24 | } | 29 | } |
25 | 30 | ||
31 | // Type returns the message type (defines the layout of the body data) | ||
26 | func (mh *MessageHeader) Type() uint16 { | 32 | func (mh *MessageHeader) Type() uint16 { |
27 | return mh.MsgType | 33 | return mh.MsgType |
28 | } | 34 | } |
29 | 35 | ||
36 | // GetMsgHeader returns the header of a message from a byte array (as the | ||
37 | // serialized form). | ||
30 | func GetMsgHeader(b []byte) (mh *MessageHeader, err error) { | 38 | func GetMsgHeader(b []byte) (mh *MessageHeader, err error) { |
31 | if b == nil || len(b) < 4 { | 39 | if b == nil || len(b) < 4 { |
32 | return nil, ErrMsgHeaderTooSmall | 40 | return nil, ErrMsgHeaderTooSmall |
diff --git a/src/gnunet/message/msg_core.go b/src/gnunet/message/msg_core.go index 0ddbd8b..538fcea 100644 --- a/src/gnunet/message/msg_core.go +++ b/src/gnunet/message/msg_core.go | |||
@@ -5,21 +5,25 @@ import ( | |||
5 | "fmt" | 5 | "fmt" |
6 | "time" | 6 | "time" |
7 | 7 | ||
8 | "github.com/bfix/gospel/crypto/ed25519" | 8 | "gnunet/crypto" |
9 | "github.com/bfix/gospel/data" | ||
10 | "gnunet/enums" | 9 | "gnunet/enums" |
11 | "gnunet/util" | 10 | "gnunet/util" |
11 | |||
12 | "github.com/bfix/gospel/crypto/ed25519" | ||
13 | "github.com/bfix/gospel/data" | ||
12 | ) | 14 | ) |
13 | 15 | ||
16 | // EphKeyBlock defines the layout of signed ephemeral key with attributes. | ||
14 | type EphKeyBlock struct { | 17 | type EphKeyBlock struct { |
15 | SignSize uint32 `order:"big"` // length of signed block | 18 | Purpose *crypto.SignaturePurpose // signature purpose: SIG_ECC_KEY |
16 | SigPurpose uint32 `order:"big"` // signature purpose: SIG_ECC_KEY | 19 | CreateTime util.AbsoluteTime // Time of key creation |
17 | CreateTime util.AbsoluteTime // Time of key creation | 20 | ExpireTime util.RelativeTime // Time to live for key |
18 | ExpireTime util.RelativeTime // Time to live for key | 21 | EphemeralKey []byte `size:"32"` // Ephemeral EdDSA public key |
19 | EphemeralKey []byte `size:"32"` // Ephemeral EdDSA public key | 22 | PeerID *util.PeerID // Peer identity (EdDSA public key) |
20 | PeerID *util.PeerID // Peer identity (EdDSA public key) | ||
21 | } | 23 | } |
22 | 24 | ||
25 | // EphemeralKeyMsg announces a new transient key for a peer. The key is signed | ||
26 | // by the issuing peer. | ||
23 | type EphemeralKeyMsg struct { | 27 | type EphemeralKeyMsg struct { |
24 | MsgSize uint16 `order:"big"` // total size of message | 28 | MsgSize uint16 `order:"big"` // total size of message |
25 | MsgType uint16 `order:"big"` // CORE_EPHEMERAL_KEY (88) | 29 | MsgType uint16 `order:"big"` // CORE_EPHEMERAL_KEY (88) |
@@ -28,6 +32,7 @@ type EphemeralKeyMsg struct { | |||
28 | SignedBlock *EphKeyBlock | 32 | SignedBlock *EphKeyBlock |
29 | } | 33 | } |
30 | 34 | ||
35 | // NewEphemeralKeyMsg creates an empty message for key announcement. | ||
31 | func NewEphemeralKeyMsg() *EphemeralKeyMsg { | 36 | func NewEphemeralKeyMsg() *EphemeralKeyMsg { |
32 | return &EphemeralKeyMsg{ | 37 | return &EphemeralKeyMsg{ |
33 | MsgSize: 160, | 38 | MsgSize: 160, |
@@ -35,8 +40,10 @@ func NewEphemeralKeyMsg() *EphemeralKeyMsg { | |||
35 | SenderStatus: 1, | 40 | SenderStatus: 1, |
36 | Signature: make([]byte, 64), | 41 | Signature: make([]byte, 64), |
37 | SignedBlock: &EphKeyBlock{ | 42 | SignedBlock: &EphKeyBlock{ |
38 | SignSize: 88, | 43 | Purpose: &crypto.SignaturePurpose{ |
39 | SigPurpose: enums.SIG_ECC_KEY, | 44 | Size: 88, |
45 | Purpose: enums.SIG_ECC_KEY, | ||
46 | }, | ||
40 | CreateTime: util.AbsoluteTimeNow(), | 47 | CreateTime: util.AbsoluteTimeNow(), |
41 | ExpireTime: util.NewRelativeTime(12 * time.Hour), | 48 | ExpireTime: util.NewRelativeTime(12 * time.Hour), |
42 | EphemeralKey: make([]byte, 32), | 49 | EphemeralKey: make([]byte, 32), |
@@ -45,6 +52,7 @@ func NewEphemeralKeyMsg() *EphemeralKeyMsg { | |||
45 | } | 52 | } |
46 | } | 53 | } |
47 | 54 | ||
55 | // String returns a human-readable representation of the message. | ||
48 | func (m *EphemeralKeyMsg) String() string { | 56 | func (m *EphemeralKeyMsg) String() string { |
49 | return fmt.Sprintf("EphKeyMsg{peer=%s,ephkey=%s,create=%s,expire=%s,status=%d}", | 57 | return fmt.Sprintf("EphKeyMsg{peer=%s,ephkey=%s,create=%s,expire=%s,status=%d}", |
50 | util.EncodeBinaryToString(m.SignedBlock.PeerID.Key), | 58 | util.EncodeBinaryToString(m.SignedBlock.PeerID.Key), |
@@ -58,10 +66,13 @@ func (msg *EphemeralKeyMsg) Header() *MessageHeader { | |||
58 | return &MessageHeader{msg.MsgSize, msg.MsgType} | 66 | return &MessageHeader{msg.MsgSize, msg.MsgType} |
59 | } | 67 | } |
60 | 68 | ||
69 | // Public extracts the public key of an announcing peer. | ||
61 | func (m *EphemeralKeyMsg) Public() *ed25519.PublicKey { | 70 | func (m *EphemeralKeyMsg) Public() *ed25519.PublicKey { |
62 | return ed25519.NewPublicKeyFromBytes(m.SignedBlock.PeerID.Key) | 71 | return ed25519.NewPublicKeyFromBytes(m.SignedBlock.PeerID.Key) |
63 | } | 72 | } |
64 | 73 | ||
74 | // Verify the integrity of the message data using the public key of the | ||
75 | // announcing peer. | ||
65 | func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey) (bool, error) { | 76 | func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey) (bool, error) { |
66 | data, err := data.Marshal(m.SignedBlock) | 77 | data, err := data.Marshal(m.SignedBlock) |
67 | if err != nil { | 78 | if err != nil { |
@@ -74,6 +85,8 @@ func (m *EphemeralKeyMsg) Verify(pub *ed25519.PublicKey) (bool, error) { | |||
74 | return pub.EdVerify(data, sig) | 85 | return pub.EdVerify(data, sig) |
75 | } | 86 | } |
76 | 87 | ||
88 | // NewEphemeralKey creates a new ephemeral key signed by a long-term private | ||
89 | // key and the corresponding GNUnet message to announce the new key. | ||
77 | func NewEphemeralKey(peerId []byte, ltPrv *ed25519.PrivateKey) (*ed25519.PrivateKey, *EphemeralKeyMsg, error) { | 90 | func NewEphemeralKey(peerId []byte, ltPrv *ed25519.PrivateKey) (*ed25519.PrivateKey, *EphemeralKeyMsg, error) { |
78 | msg := NewEphemeralKeyMsg() | 91 | msg := NewEphemeralKeyMsg() |
79 | copy(msg.SignedBlock.PeerID.Key, peerId) | 92 | copy(msg.SignedBlock.PeerID.Key, peerId) |
diff --git a/src/gnunet/message/msg_dht.go b/src/gnunet/message/msg_dht.go index bd3475a..b1d28ba 100644 --- a/src/gnunet/message/msg_dht.go +++ b/src/gnunet/message/msg_dht.go | |||
@@ -51,6 +51,7 @@ func (m *DHTClientGetMsg) SetXQuery(xq []byte) []byte { | |||
51 | return prev | 51 | return prev |
52 | } | 52 | } |
53 | 53 | ||
54 | // String returns a human-readable representation of the message. | ||
54 | func (m *DHTClientGetMsg) String() string { | 55 | func (m *DHTClientGetMsg) String() string { |
55 | return fmt.Sprintf("DHTClientGetMsg{Id:%d,Type=%d,Options=%d,Repl=%d,Key=%s}", | 56 | return fmt.Sprintf("DHTClientGetMsg{Id:%d,Type=%d,Options=%d,Repl=%d,Key=%s}", |
56 | m.Id, m.Type, m.Options, m.ReplLevel, hex.EncodeToString(m.Key.Bits)) | 57 | m.Id, m.Type, m.Options, m.ReplLevel, hex.EncodeToString(m.Key.Bits)) |
@@ -98,6 +99,7 @@ func NewDHTClientResultMsg(key *crypto.HashCode) *DHTClientResultMsg { | |||
98 | } | 99 | } |
99 | } | 100 | } |
100 | 101 | ||
102 | // String returns a human-readable representation of the message. | ||
101 | func (m *DHTClientResultMsg) String() string { | 103 | func (m *DHTClientResultMsg) String() string { |
102 | return fmt.Sprintf("DHTClientResultMsg{id:%d,expire=%s}", m.Id, m.Expire) | 104 | return fmt.Sprintf("DHTClientResultMsg{id:%d,expire=%s}", m.Id, m.Expire) |
103 | } | 105 | } |
diff --git a/src/gnunet/message/msg_gns.go b/src/gnunet/message/msg_gns.go index 0ff34be..b01c410 100644 --- a/src/gnunet/message/msg_gns.go +++ b/src/gnunet/message/msg_gns.go | |||
@@ -3,9 +3,10 @@ package message | |||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | 5 | ||
6 | "github.com/bfix/gospel/logger" | ||
7 | "gnunet/enums" | 6 | "gnunet/enums" |
8 | "gnunet/util" | 7 | "gnunet/util" |
8 | |||
9 | "github.com/bfix/gospel/logger" | ||
9 | ) | 10 | ) |
10 | 11 | ||
11 | //---------------------------------------------------------------------- | 12 | //---------------------------------------------------------------------- |
@@ -38,13 +39,13 @@ func NewGNSLookupMsg() *GNSLookupMsg { | |||
38 | } | 39 | } |
39 | } | 40 | } |
40 | 41 | ||
41 | // SetName | 42 | // SetName appends the name to lookup to the message |
42 | func (m *GNSLookupMsg) SetName(name string) { | 43 | func (m *GNSLookupMsg) SetName(name string) { |
43 | m.Name = util.Clone(append([]byte(name), 0)) | 44 | m.Name = util.Clone(append([]byte(name), 0)) |
44 | m.MsgSize = uint16(48 + len(m.Name)) | 45 | m.MsgSize = uint16(48 + len(m.Name)) |
45 | } | 46 | } |
46 | 47 | ||
47 | // GetName | 48 | // GetName returns the name to lookup from the message |
48 | func (m *GNSLookupMsg) GetName() string { | 49 | func (m *GNSLookupMsg) GetName() string { |
49 | size := len(m.Name) | 50 | size := len(m.Name) |
50 | if m.Name[size-1] != 0 { | 51 | if m.Name[size-1] != 0 { |
@@ -55,7 +56,7 @@ func (m *GNSLookupMsg) GetName() string { | |||
55 | return string(m.Name[:size]) | 56 | return string(m.Name[:size]) |
56 | } | 57 | } |
57 | 58 | ||
58 | // String | 59 | // String returns a human-readable representation of the message. |
59 | func (m *GNSLookupMsg) String() string { | 60 | func (m *GNSLookupMsg) String() string { |
60 | return fmt.Sprintf( | 61 | return fmt.Sprintf( |
61 | "GNSLookupMsg{Id=%d,Zone=%s,Options=%d,Type=%d,Name=%s}", | 62 | "GNSLookupMsg{Id=%d,Zone=%s,Options=%d,Type=%d,Name=%s}", |
@@ -72,6 +73,8 @@ func (msg *GNSLookupMsg) Header() *MessageHeader { | |||
72 | // GNS_LOOKUP_RESULT | 73 | // GNS_LOOKUP_RESULT |
73 | //---------------------------------------------------------------------- | 74 | //---------------------------------------------------------------------- |
74 | 75 | ||
76 | // GNSResourceRecord is the GNUnet-specific representation of resource | ||
77 | // records (not to be confused with DNS resource records). | ||
75 | type GNSResourceRecord struct { | 78 | type GNSResourceRecord struct { |
76 | Expires util.AbsoluteTime // Expiration time for the record | 79 | Expires util.AbsoluteTime // Expiration time for the record |
77 | Size uint32 `order:"big"` // Number of bytes in 'Data' | 80 | Size uint32 `order:"big"` // Number of bytes in 'Data' |
@@ -80,6 +83,7 @@ type GNSResourceRecord struct { | |||
80 | Data []byte `size:"Size"` // Record data | 83 | Data []byte `size:"Size"` // Record data |
81 | } | 84 | } |
82 | 85 | ||
86 | // String returns a human-readable representation of the message. | ||
83 | func (r *GNSResourceRecord) String() string { | 87 | func (r *GNSResourceRecord) String() string { |
84 | return fmt.Sprintf("GNSResourceRecord{type=%s,expire=%s,flags=%d,size=%d}", | 88 | return fmt.Sprintf("GNSResourceRecord{type=%s,expire=%s,flags=%d,size=%d}", |
85 | enums.GNS_TYPE[int(r.Type)], r.Expires, r.Flags, r.Size) | 89 | enums.GNS_TYPE[int(r.Type)], r.Expires, r.Flags, r.Size) |
@@ -105,7 +109,7 @@ func NewGNSLookupResultMsg(id uint32) *GNSLookupResultMsg { | |||
105 | } | 109 | } |
106 | } | 110 | } |
107 | 111 | ||
108 | // AddRecord | 112 | // AddRecord adds a GNS resource recordto the response message. |
109 | func (m *GNSLookupResultMsg) AddRecord(rec *GNSResourceRecord) error { | 113 | func (m *GNSLookupResultMsg) AddRecord(rec *GNSResourceRecord) error { |
110 | recSize := 20 + int(rec.Size) | 114 | recSize := 20 + int(rec.Size) |
111 | if int(m.MsgSize)+recSize > enums.GNS_MAX_BLOCK_SIZE { | 115 | if int(m.MsgSize)+recSize > enums.GNS_MAX_BLOCK_SIZE { |
@@ -117,7 +121,7 @@ func (m *GNSLookupResultMsg) AddRecord(rec *GNSResourceRecord) error { | |||
117 | return nil | 121 | return nil |
118 | } | 122 | } |
119 | 123 | ||
120 | // String | 124 | // String returns a human-readable representation of the message. |
121 | func (m *GNSLookupResultMsg) String() string { | 125 | func (m *GNSLookupResultMsg) String() string { |
122 | return fmt.Sprintf("GNSLookupResultMsg{Id=%d,Count=%d}", m.Id, m.Count) | 126 | return fmt.Sprintf("GNSLookupResultMsg{Id=%d,Count=%d}", m.Id, m.Count) |
123 | } | 127 | } |
diff --git a/src/gnunet/message/msg_namecache.go b/src/gnunet/message/msg_namecache.go index 8f82622..9e3312d 100644 --- a/src/gnunet/message/msg_namecache.go +++ b/src/gnunet/message/msg_namecache.go | |||
@@ -33,7 +33,7 @@ func NewNamecacheLookupMsg(query *crypto.HashCode) *NamecacheLookupMsg { | |||
33 | } | 33 | } |
34 | } | 34 | } |
35 | 35 | ||
36 | // String | 36 | // String returns a human-readable representation of the message. |
37 | func (m *NamecacheLookupMsg) String() string { | 37 | func (m *NamecacheLookupMsg) String() string { |
38 | return fmt.Sprintf("NamecacheLookupMsg{Id=%d,Query=%s}", | 38 | return fmt.Sprintf("NamecacheLookupMsg{Id=%d,Query=%s}", |
39 | m.Id, hex.EncodeToString(m.Query.Bits)) | 39 | m.Id, hex.EncodeToString(m.Query.Bits)) |
@@ -72,7 +72,7 @@ func NewNamecacheLookupResultMsg() *NamecacheLookupResultMsg { | |||
72 | } | 72 | } |
73 | } | 73 | } |
74 | 74 | ||
75 | // String | 75 | // String returns a human-readable representation of the message. |
76 | func (m *NamecacheLookupResultMsg) String() string { | 76 | func (m *NamecacheLookupResultMsg) String() string { |
77 | return fmt.Sprintf("NamecacheLookupResultMsg{id=%d,expire=%s}", | 77 | return fmt.Sprintf("NamecacheLookupResultMsg{id=%d,expire=%s}", |
78 | m.Id, m.Expire) | 78 | m.Id, m.Expire) |
diff --git a/src/gnunet/message/msg_transport.go b/src/gnunet/message/msg_transport.go index 1459d6a..54e63f2 100644 --- a/src/gnunet/message/msg_transport.go +++ b/src/gnunet/message/msg_transport.go | |||
@@ -4,22 +4,26 @@ import ( | |||
4 | "fmt" | 4 | "fmt" |
5 | "time" | 5 | "time" |
6 | 6 | ||
7 | "github.com/bfix/gospel/crypto/ed25519" | 7 | "gnunet/crypto" |
8 | "github.com/bfix/gospel/data" | ||
9 | "gnunet/enums" | 8 | "gnunet/enums" |
10 | "gnunet/util" | 9 | "gnunet/util" |
10 | |||
11 | "github.com/bfix/gospel/crypto/ed25519" | ||
12 | "github.com/bfix/gospel/data" | ||
11 | ) | 13 | ) |
12 | 14 | ||
13 | //---------------------------------------------------------------------- | 15 | //---------------------------------------------------------------------- |
14 | // TRANSPORT_TCP_WELCOME | 16 | // TRANSPORT_TCP_WELCOME |
15 | //---------------------------------------------------------------------- | 17 | //---------------------------------------------------------------------- |
16 | 18 | ||
19 | // TransportTcpWelcomeMsg | ||
17 | type TransportTcpWelcomeMsg struct { | 20 | type TransportTcpWelcomeMsg struct { |
18 | MsgSize uint16 `order:"big"` // total size of message | 21 | MsgSize uint16 `order:"big"` // total size of message |
19 | MsgType uint16 `order:"big"` // TRANSPORT_TCP_WELCOME (61) | 22 | MsgType uint16 `order:"big"` // TRANSPORT_TCP_WELCOME (61) |
20 | PeerID *util.PeerID // Peer identity (EdDSA public key) | 23 | PeerID *util.PeerID // Peer identity (EdDSA public key) |
21 | } | 24 | } |
22 | 25 | ||
26 | // NewTransportTcpWelcomeMsg creates a new message for a given peer. | ||
23 | func NewTransportTcpWelcomeMsg(peerid *util.PeerID) *TransportTcpWelcomeMsg { | 27 | func NewTransportTcpWelcomeMsg(peerid *util.PeerID) *TransportTcpWelcomeMsg { |
24 | if peerid == nil { | 28 | if peerid == nil { |
25 | peerid = util.NewPeerID(nil) | 29 | peerid = util.NewPeerID(nil) |
@@ -31,6 +35,7 @@ func NewTransportTcpWelcomeMsg(peerid *util.PeerID) *TransportTcpWelcomeMsg { | |||
31 | } | 35 | } |
32 | } | 36 | } |
33 | 37 | ||
38 | // String returns a human-readable representation of the message. | ||
34 | func (m *TransportTcpWelcomeMsg) String() string { | 39 | func (m *TransportTcpWelcomeMsg) String() string { |
35 | return fmt.Sprintf("TransportTcpWelcomeMsg{peer=%s}", m.PeerID) | 40 | return fmt.Sprintf("TransportTcpWelcomeMsg{peer=%s}", m.PeerID) |
36 | } | 41 | } |
@@ -41,6 +46,59 @@ func (msg *TransportTcpWelcomeMsg) Header() *MessageHeader { | |||
41 | } | 46 | } |
42 | 47 | ||
43 | //---------------------------------------------------------------------- | 48 | //---------------------------------------------------------------------- |
49 | // TRANSPORT_PING | ||
50 | // | ||
51 | // Message used to ask a peer to validate receipt (to check an address | ||
52 | // from a HELLO). Followed by the address we are trying to validate, | ||
53 | // or an empty address if we are just sending a PING to confirm that a | ||
54 | // connection which the receiver (of the PING) initiated is still valid. | ||
55 | //---------------------------------------------------------------------- | ||
56 | |||
57 | // TransportPingMsg | ||
58 | type TransportPingMsg struct { | ||
59 | MsgSize uint16 `order:"big"` // total size of message | ||
60 | MsgType uint16 `order:"big"` // TRANSPORT_PING (372) | ||
61 | Challenge uint32 // Challenge code (to ensure fresh reply) | ||
62 | Target *util.PeerID // EdDSA public key (long-term) of target peer | ||
63 | Address []byte `size:"*"` // encoded address | ||
64 | } | ||
65 | |||
66 | // TransportPingMsg creates a new message for given peer with an address to | ||
67 | // be validated. | ||
68 | func NewTransportPingMsg(target *util.PeerID, a *util.Address) *TransportPingMsg { | ||
69 | if target == nil { | ||
70 | target = util.NewPeerID(nil) | ||
71 | } | ||
72 | m := &TransportPingMsg{ | ||
73 | MsgSize: uint16(40), | ||
74 | MsgType: TRANSPORT_PING, | ||
75 | Challenge: util.RndUInt32(), | ||
76 | Target: target, | ||
77 | Address: nil, | ||
78 | } | ||
79 | if a != nil { | ||
80 | if addrData, err := data.Marshal(a); err == nil { | ||
81 | m.Address = addrData | ||
82 | m.MsgSize += uint16(len(addrData)) | ||
83 | } | ||
84 | } | ||
85 | return m | ||
86 | } | ||
87 | |||
88 | // String returns a human-readable representation of the message. | ||
89 | func (m *TransportPingMsg) String() string { | ||
90 | a := new(util.Address) | ||
91 | data.Unmarshal(a, m.Address) | ||
92 | return fmt.Sprintf("TransportPingMsg{target=%s,addr=%s,challenge=%d}", | ||
93 | m.Target, a, m.Challenge) | ||
94 | } | ||
95 | |||
96 | // Header returns the message header in a separate instance. | ||
97 | func (msg *TransportPingMsg) Header() *MessageHeader { | ||
98 | return &MessageHeader{msg.MsgSize, msg.MsgType} | ||
99 | } | ||
100 | |||
101 | //---------------------------------------------------------------------- | ||
44 | // TRANSPORT_PONG | 102 | // TRANSPORT_PONG |
45 | // | 103 | // |
46 | // Message used to validate a HELLO. The challenge is included in the | 104 | // Message used to validate a HELLO. The challenge is included in the |
@@ -53,29 +111,33 @@ func (msg *TransportTcpWelcomeMsg) Header() *MessageHeader { | |||
53 | // a connection that we initiated). | 111 | // a connection that we initiated). |
54 | //---------------------------------------------------------------------- | 112 | //---------------------------------------------------------------------- |
55 | 113 | ||
114 | // SignedAddress is the signed block of data representing a node address | ||
56 | type SignedAddress struct { | 115 | type SignedAddress struct { |
57 | SignLength uint32 `order:"big"` // Length of signed block | 116 | Purpose *crypto.SignaturePurpose // SIG_TRANSPORT_PONG_OWN |
58 | Purpose uint32 `order:"big"` // SIG_TRANSPORT_PONG_OWN | 117 | ExpireOn util.AbsoluteTime // usec epoch |
59 | ExpireOn util.AbsoluteTime // usec epoch | 118 | AddrSize uint32 `order:"big"` // size of address |
60 | AddrSize uint32 `order:"big"` // size of address | 119 | Address []byte `size:"AddrSize"` // address |
61 | Address []byte `size:"AddrSize"` // address | ||
62 | } | 120 | } |
63 | 121 | ||
122 | // NewSignedAddress creates a new (signable) data block from an address. | ||
64 | func NewSignedAddress(a *util.Address) *SignedAddress { | 123 | func NewSignedAddress(a *util.Address) *SignedAddress { |
65 | // serialize address | 124 | // serialize address |
66 | addrData, _ := data.Marshal(a) | 125 | addrData, _ := data.Marshal(a) |
67 | alen := len(addrData) | 126 | alen := len(addrData) |
68 | addr := &SignedAddress{ | 127 | addr := &SignedAddress{ |
69 | SignLength: uint32(alen + 20), | 128 | Purpose: &crypto.SignaturePurpose{ |
70 | Purpose: enums.SIG_TRANSPORT_PONG_OWN, | 129 | Size: uint32(alen + 20), |
71 | ExpireOn: util.AbsoluteTimeNow().Add(12 * time.Hour), | 130 | Purpose: enums.SIG_TRANSPORT_PONG_OWN, |
72 | AddrSize: uint32(alen), | 131 | }, |
73 | Address: make([]byte, alen), | 132 | ExpireOn: util.AbsoluteTimeNow().Add(12 * time.Hour), |
133 | AddrSize: uint32(alen), | ||
134 | Address: make([]byte, alen), | ||
74 | } | 135 | } |
75 | copy(addr.Address, addrData) | 136 | copy(addr.Address, addrData) |
76 | return addr | 137 | return addr |
77 | } | 138 | } |
78 | 139 | ||
140 | // TransportPongMsg | ||
79 | type TransportPongMsg struct { | 141 | type TransportPongMsg struct { |
80 | MsgSize uint16 `order:"big"` // total size of message | 142 | MsgSize uint16 `order:"big"` // total size of message |
81 | MsgType uint16 `order:"big"` // TRANSPORT_PING (372) | 143 | MsgType uint16 `order:"big"` // TRANSPORT_PING (372) |
@@ -84,6 +146,8 @@ type TransportPongMsg struct { | |||
84 | SignedBlock *SignedAddress // signed block of data | 146 | SignedBlock *SignedAddress // signed block of data |
85 | } | 147 | } |
86 | 148 | ||
149 | // NewTransportPongMsg creates a reponse message with an address the replying | ||
150 | // peer wants to be reached. | ||
87 | func NewTransportPongMsg(challenge uint32, a *util.Address) *TransportPongMsg { | 151 | func NewTransportPongMsg(challenge uint32, a *util.Address) *TransportPongMsg { |
88 | m := &TransportPongMsg{ | 152 | m := &TransportPongMsg{ |
89 | MsgSize: 72, | 153 | MsgSize: 72, |
@@ -94,12 +158,13 @@ func NewTransportPongMsg(challenge uint32, a *util.Address) *TransportPongMsg { | |||
94 | } | 158 | } |
95 | if a != nil { | 159 | if a != nil { |
96 | sa := NewSignedAddress(a) | 160 | sa := NewSignedAddress(a) |
97 | m.MsgSize += uint16(sa.SignLength) | 161 | m.MsgSize += uint16(sa.Purpose.Size) |
98 | m.SignedBlock = sa | 162 | m.SignedBlock = sa |
99 | } | 163 | } |
100 | return m | 164 | return m |
101 | } | 165 | } |
102 | 166 | ||
167 | // String returns a human-readable representation of the message. | ||
103 | func (m *TransportPongMsg) String() string { | 168 | func (m *TransportPongMsg) String() string { |
104 | a := new(util.Address) | 169 | a := new(util.Address) |
105 | if err := data.Unmarshal(a, m.SignedBlock.Address); err == nil { | 170 | if err := data.Unmarshal(a, m.SignedBlock.Address); err == nil { |
@@ -114,6 +179,7 @@ func (msg *TransportPongMsg) Header() *MessageHeader { | |||
114 | return &MessageHeader{msg.MsgSize, msg.MsgType} | 179 | return &MessageHeader{msg.MsgSize, msg.MsgType} |
115 | } | 180 | } |
116 | 181 | ||
182 | // Sign the address block of a pong message. | ||
117 | func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey) error { | 183 | func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey) error { |
118 | data, err := data.Marshal(m.SignedBlock) | 184 | data, err := data.Marshal(m.SignedBlock) |
119 | if err != nil { | 185 | if err != nil { |
@@ -127,6 +193,7 @@ func (m *TransportPongMsg) Sign(prv *ed25519.PrivateKey) error { | |||
127 | return nil | 193 | return nil |
128 | } | 194 | } |
129 | 195 | ||
196 | // Verify the address block of a pong message | ||
130 | func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey) (bool, error) { | 197 | func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey) (bool, error) { |
131 | data, err := data.Marshal(m.SignedBlock) | 198 | data, err := data.Marshal(m.SignedBlock) |
132 | if err != nil { | 199 | if err != nil { |
@@ -140,55 +207,6 @@ func (m *TransportPongMsg) Verify(pub *ed25519.PublicKey) (bool, error) { | |||
140 | } | 207 | } |
141 | 208 | ||
142 | //---------------------------------------------------------------------- | 209 | //---------------------------------------------------------------------- |
143 | // TRANSPORT_PING | ||
144 | // | ||
145 | // Message used to ask a peer to validate receipt (to check an address | ||
146 | // from a HELLO). Followed by the address we are trying to validate, | ||
147 | // or an empty address if we are just sending a PING to confirm that a | ||
148 | // connection which the receiver (of the PING) initiated is still valid. | ||
149 | //---------------------------------------------------------------------- | ||
150 | |||
151 | type TransportPingMsg struct { | ||
152 | MsgSize uint16 `order:"big"` // total size of message | ||
153 | MsgType uint16 `order:"big"` // TRANSPORT_PING (372) | ||
154 | Challenge uint32 // Challenge code (to ensure fresh reply) | ||
155 | Target *util.PeerID // EdDSA public key (long-term) of target peer | ||
156 | Address []byte `size:"*"` // encoded address | ||
157 | } | ||
158 | |||
159 | func NewTransportPingMsg(target *util.PeerID, a *util.Address) *TransportPingMsg { | ||
160 | if target == nil { | ||
161 | target = util.NewPeerID(nil) | ||
162 | } | ||
163 | m := &TransportPingMsg{ | ||
164 | MsgSize: uint16(40), | ||
165 | MsgType: TRANSPORT_PING, | ||
166 | Challenge: util.RndUInt32(), | ||
167 | Target: target, | ||
168 | Address: nil, | ||
169 | } | ||
170 | if a != nil { | ||
171 | if addrData, err := data.Marshal(a); err == nil { | ||
172 | m.Address = addrData | ||
173 | m.MsgSize += uint16(len(addrData)) | ||
174 | } | ||
175 | } | ||
176 | return m | ||
177 | } | ||
178 | |||
179 | func (m *TransportPingMsg) String() string { | ||
180 | a := new(util.Address) | ||
181 | data.Unmarshal(a, m.Address) | ||
182 | return fmt.Sprintf("TransportPingMsg{target=%s,addr=%s,challenge=%d}", | ||
183 | m.Target, a, m.Challenge) | ||
184 | } | ||
185 | |||
186 | // Header returns the message header in a separate instance. | ||
187 | func (msg *TransportPingMsg) Header() *MessageHeader { | ||
188 | return &MessageHeader{msg.MsgSize, msg.MsgType} | ||
189 | } | ||
190 | |||
191 | //---------------------------------------------------------------------- | ||
192 | // HELLO | 210 | // HELLO |
193 | // | 211 | // |
194 | // A HELLO message is used to exchange information about | 212 | // A HELLO message is used to exchange information about |
@@ -202,6 +220,7 @@ func (msg *TransportPingMsg) Header() *MessageHeader { | |||
202 | // 4) address (address-length bytes) | 220 | // 4) address (address-length bytes) |
203 | //---------------------------------------------------------------------- | 221 | //---------------------------------------------------------------------- |
204 | 222 | ||
223 | // HelloAddress | ||
205 | type HelloAddress struct { | 224 | type HelloAddress struct { |
206 | Transport string // Name of transport | 225 | Transport string // Name of transport |
207 | AddrSize uint16 `order:"big"` // Size of address entry | 226 | AddrSize uint16 `order:"big"` // Size of address entry |
@@ -209,6 +228,7 @@ type HelloAddress struct { | |||
209 | Address []byte `size:"AddrSize"` // Address specification | 228 | Address []byte `size:"AddrSize"` // Address specification |
210 | } | 229 | } |
211 | 230 | ||
231 | // NewHelloAddress create a new HELLO address from the given address | ||
212 | func NewAddress(a *util.Address) *HelloAddress { | 232 | func NewAddress(a *util.Address) *HelloAddress { |
213 | addr := &HelloAddress{ | 233 | addr := &HelloAddress{ |
214 | Transport: a.Transport, | 234 | Transport: a.Transport, |
@@ -220,11 +240,13 @@ func NewAddress(a *util.Address) *HelloAddress { | |||
220 | return addr | 240 | return addr |
221 | } | 241 | } |
222 | 242 | ||
243 | // String returns a human-readable representation of the message. | ||
223 | func (a *HelloAddress) String() string { | 244 | func (a *HelloAddress) String() string { |
224 | return fmt.Sprintf("Address{%s,expire=%s}", | 245 | return fmt.Sprintf("Address{%s,expire=%s}", |
225 | util.AddressString(a.Transport, a.Address), a.ExpireOn) | 246 | util.AddressString(a.Transport, a.Address), a.ExpireOn) |
226 | } | 247 | } |
227 | 248 | ||
249 | // HelloMsg | ||
228 | type HelloMsg struct { | 250 | type HelloMsg struct { |
229 | MsgSize uint16 `order:"big"` // total size of message | 251 | MsgSize uint16 `order:"big"` // total size of message |
230 | MsgType uint16 `order:"big"` // HELLO (17) | 252 | MsgType uint16 `order:"big"` // HELLO (17) |
@@ -233,6 +255,7 @@ type HelloMsg struct { | |||
233 | Addresses []*HelloAddress `size:"*"` // List of end-point addressess | 255 | Addresses []*HelloAddress `size:"*"` // List of end-point addressess |
234 | } | 256 | } |
235 | 257 | ||
258 | // NewHelloMsg creates a new HELLO msg for a given peer. | ||
236 | func NewHelloMsg(peerid *util.PeerID) *HelloMsg { | 259 | func NewHelloMsg(peerid *util.PeerID) *HelloMsg { |
237 | if peerid == nil { | 260 | if peerid == nil { |
238 | peerid = util.NewPeerID(nil) | 261 | peerid = util.NewPeerID(nil) |
@@ -246,11 +269,13 @@ func NewHelloMsg(peerid *util.PeerID) *HelloMsg { | |||
246 | } | 269 | } |
247 | } | 270 | } |
248 | 271 | ||
272 | // String returns a human-readable representation of the message. | ||
249 | func (m *HelloMsg) String() string { | 273 | func (m *HelloMsg) String() string { |
250 | return fmt.Sprintf("HelloMsg{peer=%s,friendsonly=%d,addr=%v}", | 274 | return fmt.Sprintf("HelloMsg{peer=%s,friendsonly=%d,addr=%v}", |
251 | m.PeerID, m.FriendOnly, m.Addresses) | 275 | m.PeerID, m.FriendOnly, m.Addresses) |
252 | } | 276 | } |
253 | 277 | ||
278 | // AddAddress adds a new address to the HELLO message. | ||
254 | func (m *HelloMsg) AddAddress(a *HelloAddress) { | 279 | func (m *HelloMsg) AddAddress(a *HelloAddress) { |
255 | m.Addresses = append(m.Addresses, a) | 280 | m.Addresses = append(m.Addresses, a) |
256 | m.MsgSize += uint16(len(a.Transport)) + a.AddrSize + 11 | 281 | m.MsgSize += uint16(len(a.Transport)) + a.AddrSize + 11 |
@@ -265,11 +290,13 @@ func (msg *HelloMsg) Header() *MessageHeader { | |||
265 | // TRANSPORT_SESSION_ACK | 290 | // TRANSPORT_SESSION_ACK |
266 | //---------------------------------------------------------------------- | 291 | //---------------------------------------------------------------------- |
267 | 292 | ||
293 | // SessionAckMsg | ||
268 | type SessionAckMsg struct { | 294 | type SessionAckMsg struct { |
269 | MsgSize uint16 `order:"big"` // total size of message | 295 | MsgSize uint16 `order:"big"` // total size of message |
270 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_ACK (377) | 296 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_ACK (377) |
271 | } | 297 | } |
272 | 298 | ||
299 | // NewSessionAckMsg creates an new message (no body required). | ||
273 | func NewSessionAckMsg() *SessionAckMsg { | 300 | func NewSessionAckMsg() *SessionAckMsg { |
274 | return &SessionAckMsg{ | 301 | return &SessionAckMsg{ |
275 | MsgSize: 16, | 302 | MsgSize: 16, |
@@ -277,6 +304,7 @@ func NewSessionAckMsg() *SessionAckMsg { | |||
277 | } | 304 | } |
278 | } | 305 | } |
279 | 306 | ||
307 | // String returns a human-readable representation of the message. | ||
280 | func (m *SessionAckMsg) String() string { | 308 | func (m *SessionAckMsg) String() string { |
281 | return "SessionAck{}" | 309 | return "SessionAck{}" |
282 | } | 310 | } |
@@ -290,6 +318,7 @@ func (msg *SessionAckMsg) Header() *MessageHeader { | |||
290 | // TRANSPORT_SESSION_SYN | 318 | // TRANSPORT_SESSION_SYN |
291 | //---------------------------------------------------------------------- | 319 | //---------------------------------------------------------------------- |
292 | 320 | ||
321 | // SessionSynMsg | ||
293 | type SessionSynMsg struct { | 322 | type SessionSynMsg struct { |
294 | MsgSize uint16 `order:"big"` // total size of message | 323 | MsgSize uint16 `order:"big"` // total size of message |
295 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN (375) | 324 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN (375) |
@@ -297,6 +326,7 @@ type SessionSynMsg struct { | |||
297 | Timestamp util.AbsoluteTime // usec epoch | 326 | Timestamp util.AbsoluteTime // usec epoch |
298 | } | 327 | } |
299 | 328 | ||
329 | // NewSessionSynMsg creates a SYN request for the a session | ||
300 | func NewSessionSynMsg() *SessionSynMsg { | 330 | func NewSessionSynMsg() *SessionSynMsg { |
301 | return &SessionSynMsg{ | 331 | return &SessionSynMsg{ |
302 | MsgSize: 16, | 332 | MsgSize: 16, |
@@ -306,6 +336,7 @@ func NewSessionSynMsg() *SessionSynMsg { | |||
306 | } | 336 | } |
307 | } | 337 | } |
308 | 338 | ||
339 | // String returns a human-readable representation of the message. | ||
309 | func (m *SessionSynMsg) String() string { | 340 | func (m *SessionSynMsg) String() string { |
310 | return fmt.Sprintf("SessionSyn{timestamp=%s}", m.Timestamp) | 341 | return fmt.Sprintf("SessionSyn{timestamp=%s}", m.Timestamp) |
311 | } | 342 | } |
@@ -319,6 +350,7 @@ func (msg *SessionSynMsg) Header() *MessageHeader { | |||
319 | // TRANSPORT_SESSION_SYN_ACK | 350 | // TRANSPORT_SESSION_SYN_ACK |
320 | //---------------------------------------------------------------------- | 351 | //---------------------------------------------------------------------- |
321 | 352 | ||
353 | // SessionSynAckMsg | ||
322 | type SessionSynAckMsg struct { | 354 | type SessionSynAckMsg struct { |
323 | MsgSize uint16 `order:"big"` // total size of message | 355 | MsgSize uint16 `order:"big"` // total size of message |
324 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN_ACK (376) | 356 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_SYN_ACK (376) |
@@ -326,6 +358,7 @@ type SessionSynAckMsg struct { | |||
326 | Timestamp util.AbsoluteTime // usec epoch | 358 | Timestamp util.AbsoluteTime // usec epoch |
327 | } | 359 | } |
328 | 360 | ||
361 | // NewSessionSynAckMsg is an ACK for a SYN request | ||
329 | func NewSessionSynAckMsg() *SessionSynAckMsg { | 362 | func NewSessionSynAckMsg() *SessionSynAckMsg { |
330 | return &SessionSynAckMsg{ | 363 | return &SessionSynAckMsg{ |
331 | MsgSize: 16, | 364 | MsgSize: 16, |
@@ -335,6 +368,7 @@ func NewSessionSynAckMsg() *SessionSynAckMsg { | |||
335 | } | 368 | } |
336 | } | 369 | } |
337 | 370 | ||
371 | // String returns a human-readable representation of the message. | ||
338 | func (m *SessionSynAckMsg) String() string { | 372 | func (m *SessionSynAckMsg) String() string { |
339 | return fmt.Sprintf("SessionSynAck{timestamp=%s}", m.Timestamp) | 373 | return fmt.Sprintf("SessionSynAck{timestamp=%s}", m.Timestamp) |
340 | } | 374 | } |
@@ -348,12 +382,14 @@ func (msg *SessionSynAckMsg) Header() *MessageHeader { | |||
348 | // TRANSPORT_SESSION_QUOTA | 382 | // TRANSPORT_SESSION_QUOTA |
349 | //---------------------------------------------------------------------- | 383 | //---------------------------------------------------------------------- |
350 | 384 | ||
385 | // SessionQuotaMsg | ||
351 | type SessionQuotaMsg struct { | 386 | type SessionQuotaMsg struct { |
352 | MsgSize uint16 `order:"big"` // total size of message | 387 | MsgSize uint16 `order:"big"` // total size of message |
353 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_QUOTA (379) | 388 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_QUOTA (379) |
354 | Quota uint32 `order:"big"` // Quota in bytes per second | 389 | Quota uint32 `order:"big"` // Quota in bytes per second |
355 | } | 390 | } |
356 | 391 | ||
392 | // NewSessionQuotaMsg announces a session quota to the other end of the session. | ||
357 | func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg { | 393 | func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg { |
358 | m := new(SessionQuotaMsg) | 394 | m := new(SessionQuotaMsg) |
359 | if quota > 0 { | 395 | if quota > 0 { |
@@ -364,6 +400,7 @@ func NewSessionQuotaMsg(quota uint32) *SessionQuotaMsg { | |||
364 | return m | 400 | return m |
365 | } | 401 | } |
366 | 402 | ||
403 | // String returns a human-readable representation of the message. | ||
367 | func (m *SessionQuotaMsg) String() string { | 404 | func (m *SessionQuotaMsg) String() string { |
368 | return fmt.Sprintf("SessionQuotaMsg{%sB/s}", util.Scale1024(uint64(m.Quota))) | 405 | return fmt.Sprintf("SessionQuotaMsg{%sB/s}", util.Scale1024(uint64(m.Quota))) |
369 | } | 406 | } |
@@ -374,57 +411,63 @@ func (msg *SessionQuotaMsg) Header() *MessageHeader { | |||
374 | } | 411 | } |
375 | 412 | ||
376 | //---------------------------------------------------------------------- | 413 | //---------------------------------------------------------------------- |
377 | // TRANSPORT_SESSION_KEEPALIVE_RESPONSE | 414 | // TRANSPORT_SESSION_KEEPALIVE |
378 | //---------------------------------------------------------------------- | 415 | //---------------------------------------------------------------------- |
379 | 416 | ||
380 | type SessionKeepAliveRespMsg struct { | 417 | // SessionKeepAliveMsg |
418 | type SessionKeepAliveMsg struct { | ||
381 | MsgSize uint16 `order:"big"` // total size of message | 419 | MsgSize uint16 `order:"big"` // total size of message |
382 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE_RESPONSE (382) | 420 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE (381) |
383 | Nonce uint32 | 421 | Nonce uint32 |
384 | } | 422 | } |
385 | 423 | ||
386 | func NewSessionKeepAliveRespMsg(nonce uint32) *SessionKeepAliveRespMsg { | 424 | // NewSessionKeepAliveMsg creates a new request to keep a session. |
387 | m := &SessionKeepAliveRespMsg{ | 425 | func NewSessionKeepAliveMsg() *SessionKeepAliveMsg { |
426 | m := &SessionKeepAliveMsg{ | ||
388 | MsgSize: 8, | 427 | MsgSize: 8, |
389 | MsgType: TRANSPORT_SESSION_KEEPALIVE_RESPONSE, | 428 | MsgType: TRANSPORT_SESSION_KEEPALIVE, |
390 | Nonce: nonce, | 429 | Nonce: util.RndUInt32(), |
391 | } | 430 | } |
392 | return m | 431 | return m |
393 | } | 432 | } |
394 | 433 | ||
395 | func (m *SessionKeepAliveRespMsg) String() string { | 434 | // String returns a human-readable representation of the message. |
396 | return fmt.Sprintf("SessionKeepAliveRespMsg{%d}", m.Nonce) | 435 | func (m *SessionKeepAliveMsg) String() string { |
436 | return fmt.Sprintf("SessionKeepAliveMsg{%d}", m.Nonce) | ||
397 | } | 437 | } |
398 | 438 | ||
399 | // Header returns the message header in a separate instance. | 439 | // Header returns the message header in a separate instance. |
400 | func (msg *SessionKeepAliveRespMsg) Header() *MessageHeader { | 440 | func (msg *SessionKeepAliveMsg) Header() *MessageHeader { |
401 | return &MessageHeader{msg.MsgSize, msg.MsgType} | 441 | return &MessageHeader{msg.MsgSize, msg.MsgType} |
402 | } | 442 | } |
403 | 443 | ||
404 | //---------------------------------------------------------------------- | 444 | //---------------------------------------------------------------------- |
405 | // TRANSPORT_SESSION_KEEPALIVE | 445 | // TRANSPORT_SESSION_KEEPALIVE_RESPONSE |
406 | //---------------------------------------------------------------------- | 446 | //---------------------------------------------------------------------- |
407 | 447 | ||
408 | type SessionKeepAliveMsg struct { | 448 | // SessionKeepAliveRespMsg |
449 | type SessionKeepAliveRespMsg struct { | ||
409 | MsgSize uint16 `order:"big"` // total size of message | 450 | MsgSize uint16 `order:"big"` // total size of message |
410 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE (381) | 451 | MsgType uint16 `order:"big"` // TRANSPORT_SESSION_KEEPALIVE_RESPONSE (382) |
411 | Nonce uint32 | 452 | Nonce uint32 |
412 | } | 453 | } |
413 | 454 | ||
414 | func NewSessionKeepAliveMsg() *SessionKeepAliveMsg { | 455 | // NewSessionKeepAliveRespMsg is a response message for a "keep session" request. |
415 | m := &SessionKeepAliveMsg{ | 456 | func NewSessionKeepAliveRespMsg(nonce uint32) *SessionKeepAliveRespMsg { |
457 | m := &SessionKeepAliveRespMsg{ | ||
416 | MsgSize: 8, | 458 | MsgSize: 8, |
417 | MsgType: TRANSPORT_SESSION_KEEPALIVE, | 459 | MsgType: TRANSPORT_SESSION_KEEPALIVE_RESPONSE, |
418 | Nonce: util.RndUInt32(), | 460 | Nonce: nonce, |
419 | } | 461 | } |
420 | return m | 462 | return m |
421 | } | 463 | } |
422 | 464 | ||
423 | func (m *SessionKeepAliveMsg) String() string { | 465 | // String returns a human-readable representation of the message. |
424 | return fmt.Sprintf("SessionKeepAliveMsg{%d}", m.Nonce) | 466 | func (m *SessionKeepAliveRespMsg) String() string { |
467 | return fmt.Sprintf("SessionKeepAliveRespMsg{%d}", m.Nonce) | ||
425 | } | 468 | } |
426 | 469 | ||
427 | // Header returns the message header in a separate instance. | 470 | // Header returns the message header in a separate instance. |
428 | func (msg *SessionKeepAliveMsg) Header() *MessageHeader { | 471 | func (msg *SessionKeepAliveRespMsg) Header() *MessageHeader { |
429 | return &MessageHeader{msg.MsgSize, msg.MsgType} | 472 | return &MessageHeader{msg.MsgSize, msg.MsgType} |
430 | } | 473 | } |
diff --git a/src/gnunet/service/client.go b/src/gnunet/service/client.go index 2d1c3dd..3bae7da 100644 --- a/src/gnunet/service/client.go +++ b/src/gnunet/service/client.go | |||
@@ -1,9 +1,10 @@ | |||
1 | package service | 1 | package service |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "github.com/bfix/gospel/logger" | ||
5 | "gnunet/message" | 4 | "gnunet/message" |
6 | "gnunet/transport" | 5 | "gnunet/transport" |
6 | |||
7 | "github.com/bfix/gospel/logger" | ||
7 | ) | 8 | ) |
8 | 9 | ||
9 | // Client | 10 | // Client |
diff --git a/src/gnunet/service/gns/block.go b/src/gnunet/service/gns/block.go new file mode 100644 index 0000000..9d83f99 --- /dev/null +++ b/src/gnunet/service/gns/block.go | |||
@@ -0,0 +1,185 @@ | |||
1 | package gns | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | "gnunet/crypto" | ||
7 | "gnunet/enums" | ||
8 | "gnunet/message" | ||
9 | "gnunet/util" | ||
10 | |||
11 | "github.com/bfix/gospel/crypto/ed25519" | ||
12 | "github.com/bfix/gospel/data" | ||
13 | ) | ||
14 | |||
15 | var ( | ||
16 | ErrBlockNotDecrypted = fmt.Errorf("GNS block not decrypted") | ||
17 | ) | ||
18 | |||
19 | //====================================================================== | ||
20 | // GNS block: An encrypted and signed container for GNS resource records | ||
21 | // that represents the "atomic" data structure associated with a GNS | ||
22 | // label in a given zone. | ||
23 | //====================================================================== | ||
24 | |||
25 | // SignedBlockData: signed and encrypted list of resource records stored | ||
26 | // in a GNSRecordSet | ||
27 | type SignedBlockData struct { | ||
28 | Purpose *crypto.SignaturePurpose // Size and purpose of signature (8 bytes) | ||
29 | Expire util.AbsoluteTime // Expiration time of the block. | ||
30 | EncData []byte `size:"*"` // encrypted GNSRecordSet | ||
31 | |||
32 | // transient data (not serialized) | ||
33 | data []byte // unencrypted GNSRecord set | ||
34 | } | ||
35 | |||
36 | // GNSBlock is the result of GNS lookups for a given label in a zone. | ||
37 | type GNSBlock struct { | ||
38 | Signature []byte `size:"64"` // Signature of the block. | ||
39 | DerivedKey []byte `size:"32"` // Derived key used for signing | ||
40 | Block *SignedBlockData | ||
41 | |||
42 | // transient data (not serialized) | ||
43 | checked bool // block integrity checked | ||
44 | verified bool // block signature verified (internal) | ||
45 | decrypted bool // block data decrypted (internal) | ||
46 | } | ||
47 | |||
48 | // String returns the human-readable representation of a GNSBlock | ||
49 | func (b *GNSBlock) String() string { | ||
50 | return fmt.Sprintf("GNSBlock{Verified=%v,Decrypted=%v,data=[%d]}", | ||
51 | b.verified, b.decrypted, len(b.Block.EncData)) | ||
52 | } | ||
53 | |||
54 | // Records returns the list of resource records in a block. | ||
55 | func (b *GNSBlock) Records() ([]*message.GNSResourceRecord, error) { | ||
56 | // check if block is decrypted | ||
57 | if !b.decrypted { | ||
58 | return nil, ErrBlockNotDecrypted | ||
59 | } | ||
60 | // parse block data into record set | ||
61 | rs := NewGNSRecordSet() | ||
62 | if err := data.Unmarshal(rs, b.Block.data); err != nil { | ||
63 | return nil, err | ||
64 | } | ||
65 | return rs.Records, nil | ||
66 | } | ||
67 | |||
68 | // Verify the integrity of the block data from a signature. | ||
69 | func (b *GNSBlock) Verify(zoneKey *ed25519.PublicKey, label string) (err error) { | ||
70 | // Integrity check performed | ||
71 | b.checked = true | ||
72 | |||
73 | // verify derived key | ||
74 | dkey := ed25519.NewPublicKeyFromBytes(b.DerivedKey) | ||
75 | dkey2 := crypto.DerivePublicKey(zoneKey, label, "gns") | ||
76 | if !dkey.Q.Equals(dkey2.Q) { | ||
77 | return fmt.Errorf("Invalid signature key for GNS Block") | ||
78 | } | ||
79 | // verify signature | ||
80 | var ( | ||
81 | sig *ed25519.EcSignature | ||
82 | buf []byte | ||
83 | ok bool | ||
84 | ) | ||
85 | if sig, err = ed25519.NewEcSignatureFromBytes(b.Signature); err != nil { | ||
86 | return | ||
87 | } | ||
88 | if buf, err = data.Marshal(b.Block); err != nil { | ||
89 | return | ||
90 | } | ||
91 | if ok, err = dkey.EcVerify(buf, sig); err == nil && !ok { | ||
92 | err = fmt.Errorf("Signature verification failed for GNS block") | ||
93 | } | ||
94 | b.verified = true | ||
95 | return | ||
96 | } | ||
97 | |||
98 | // Decrypt block data with a key/iv combination derived from (PKEY,label) | ||
99 | func (b *GNSBlock) Decrypt(zoneKey *ed25519.PublicKey, label string) (err error) { | ||
100 | // decrypt payload | ||
101 | b.Block.data, err = crypto.DecryptBlock(b.Block.EncData, zoneKey, label) | ||
102 | b.decrypted = true | ||
103 | return | ||
104 | } | ||
105 | |||
106 | // NewGNSBlock instantiates an empty GNS block | ||
107 | func NewGNSBlock() *GNSBlock { | ||
108 | return &GNSBlock{ | ||
109 | Signature: make([]byte, 64), | ||
110 | DerivedKey: make([]byte, 32), | ||
111 | Block: &SignedBlockData{ | ||
112 | Purpose: new(crypto.SignaturePurpose), | ||
113 | Expire: *new(util.AbsoluteTime), | ||
114 | EncData: nil, | ||
115 | data: nil, | ||
116 | }, | ||
117 | checked: false, | ||
118 | verified: false, | ||
119 | decrypted: false, | ||
120 | } | ||
121 | } | ||
122 | |||
123 | //---------------------------------------------------------------------- | ||
124 | // GNSRecordSet | ||
125 | //---------------------------------------------------------------------- | ||
126 | |||
127 | // GNSRecordSet ist the GNUnet data structure for a list of resource records | ||
128 | // in a GNSBlock. As part of GNUnet messages, the record set is padded so that | ||
129 | // the binary size of (records||padding) is the smallest power of two. | ||
130 | type GNSRecordSet struct { | ||
131 | Count uint32 `order:"big"` // number of resource records | ||
132 | Records []*message.GNSResourceRecord `size:"Count"` // list of resource records | ||
133 | Padding []byte `size:"*"` // padding | ||
134 | } | ||
135 | |||
136 | // NewGNSRecordSet returns an empty resource record set. | ||
137 | func NewGNSRecordSet() *GNSRecordSet { | ||
138 | return &GNSRecordSet{ | ||
139 | Count: 0, | ||
140 | Records: make([]*message.GNSResourceRecord, 0), | ||
141 | Padding: make([]byte, 0), | ||
142 | } | ||
143 | } | ||
144 | |||
145 | // AddRecord to append a resource record to the set. | ||
146 | func (rs *GNSRecordSet) AddRecord(rec *message.GNSResourceRecord) { | ||
147 | rs.Count++ | ||
148 | rs.Records = append(rs.Records, rec) | ||
149 | } | ||
150 | |||
151 | //====================================================================== | ||
152 | // List of resource records types (for GNS/DNS queries) | ||
153 | //====================================================================== | ||
154 | |||
155 | // RRTypeList is a list of integers representing RR types. | ||
156 | type RRTypeList []int | ||
157 | |||
158 | // Initialize a new type list with given type values | ||
159 | func NewRRTypeList(args ...int) (res RRTypeList) { | ||
160 | for _, val := range args { | ||
161 | // if GNS_TYPE_ANY is encountered, it becomes the sole type | ||
162 | if val == enums.GNS_TYPE_ANY { | ||
163 | res = make(RRTypeList, 1) | ||
164 | res[0] = val | ||
165 | return | ||
166 | } | ||
167 | res = append(res, val) | ||
168 | } | ||
169 | return | ||
170 | } | ||
171 | |||
172 | // HasType returns true if the type is included in the list | ||
173 | func (tl RRTypeList) HasType(t int) bool { | ||
174 | // return true if type is GNS_TYPE_ANY | ||
175 | if tl[0] == enums.GNS_TYPE_ANY { | ||
176 | return true | ||
177 | } | ||
178 | // check for type in list | ||
179 | for _, val := range tl { | ||
180 | if val == t { | ||
181 | return true | ||
182 | } | ||
183 | } | ||
184 | return false | ||
185 | } | ||
diff --git a/src/gnunet/service/gns/block_handler.go b/src/gnunet/service/gns/block_handler.go new file mode 100644 index 0000000..860b4a7 --- /dev/null +++ b/src/gnunet/service/gns/block_handler.go | |||
@@ -0,0 +1,398 @@ | |||
1 | package gns | ||
2 | |||
3 | import ( | ||
4 | "encoding/hex" | ||
5 | "fmt" | ||
6 | |||
7 | "gnunet/enums" | ||
8 | "gnunet/message" | ||
9 | |||
10 | "github.com/bfix/gospel/crypto/ed25519" | ||
11 | "github.com/bfix/gospel/logger" | ||
12 | ) | ||
13 | |||
14 | // HdlrInst is the type for functions that instanciate custom block handlers. | ||
15 | type HdlrInst func(*message.GNSResourceRecord, []string) (BlockHandler, error) | ||
16 | |||
17 | // Error codes | ||
18 | var ( | ||
19 | ErrInvalidRecordMix = fmt.Errorf("Invalid mix of RR types in block") | ||
20 | ErrBlockHandler = fmt.Errorf("Internal block handler failure") | ||
21 | ) | ||
22 | |||
23 | // Mapping of RR types to BlockHandler instanciation functions | ||
24 | var ( | ||
25 | customHandler = map[int]HdlrInst{ | ||
26 | enums.GNS_TYPE_PKEY: NewPkeyHandler, | ||
27 | enums.GNS_TYPE_GNS2DNS: NewGns2DnsHandler, | ||
28 | enums.GNS_TYPE_BOX: NewBoxHandler, | ||
29 | enums.GNS_TYPE_LEHO: NewLehoHandler, | ||
30 | } | ||
31 | ) | ||
32 | |||
33 | //====================================================================== | ||
34 | // GNS blocks that contain special records (PKEY, GNS2DNS, BOX, LEHO...) | ||
35 | // require special treatment with respect to other resource records with | ||
36 | // different types in the same block. Usually only certain other types | ||
37 | // (or none at all) are allowed. | ||
38 | //====================================================================== | ||
39 | |||
40 | // BlockHandler interface. | ||
41 | type BlockHandler interface { | ||
42 | // AddRecord inserts a RR into the BlockHandler for (later) processing. | ||
43 | // The handler can inspect the remaining labels in a path if required. | ||
44 | // It returns an error if a record is not accepted by the block handler. | ||
45 | AddRecord(rr *message.GNSResourceRecord, labels []string) error | ||
46 | |||
47 | // TypeAction returns a flag indicating how a resource record of a | ||
48 | // given type is to be treated by a custom block handler: | ||
49 | // = -1: Record is not allowed | ||
50 | // = 0: Record is allowed but will be ignored | ||
51 | // = 1: Record is allowed and will be processed | ||
52 | TypeAction(t int) int | ||
53 | |||
54 | // Records returns a list of RR of the given types associated with | ||
55 | // the custom handler | ||
56 | Records(kind RRTypeList) *GNSRecordSet | ||
57 | } | ||
58 | |||
59 | //---------------------------------------------------------------------- | ||
60 | // Manage list of block handlers | ||
61 | // Under normal circumstances there is only one (or none) block handler | ||
62 | // per block, but future constructs may allow multiple block handlers | ||
63 | // to be present. The block handler list implements the BlockHandler | ||
64 | // interface. | ||
65 | // The BlockHandlerList maintains a map of actually instantiated handlers | ||
66 | // (indexed by record type) and a list of record types (with occurrence | ||
67 | // count) in the block. | ||
68 | //---------------------------------------------------------------------- | ||
69 | |||
70 | // BlockHandlerList is a list of block handlers instantiated. | ||
71 | type BlockHandlerList struct { | ||
72 | list map[int]BlockHandler // list of handler instances | ||
73 | } | ||
74 | |||
75 | // NewBlockHandlerList instantiates an a list of active block handlers | ||
76 | // for a given set of records (GNS block). | ||
77 | func NewBlockHandlerList(records []*message.GNSResourceRecord, labels []string) (*BlockHandlerList, error) { | ||
78 | // initialize block handler list | ||
79 | hl := &BlockHandlerList{ | ||
80 | list: make(map[int]BlockHandler), | ||
81 | } | ||
82 | // build a list of record types that are handled by a custom handler. | ||
83 | rrList := NewRRTypeList( | ||
84 | enums.GNS_TYPE_PKEY, | ||
85 | enums.GNS_TYPE_GNS2DNS, | ||
86 | enums.GNS_TYPE_BOX, | ||
87 | enums.GNS_TYPE_LEHO) | ||
88 | |||
89 | // Traverse record list and build list of handler instances | ||
90 | for _, rec := range records { | ||
91 | // check for custom handler type | ||
92 | rrType := int(rec.Type) | ||
93 | if rrList.HasType(rrType) { | ||
94 | // check if a handler for given type already exists | ||
95 | var ( | ||
96 | hdlr BlockHandler | ||
97 | ok bool | ||
98 | err error | ||
99 | ) | ||
100 | if hdlr, ok = hl.list[rrType]; ok { | ||
101 | // add record to existing handler | ||
102 | if err = hdlr.AddRecord(rec, labels); err != nil { | ||
103 | return nil, err | ||
104 | } | ||
105 | continue | ||
106 | } | ||
107 | // create a new handler instance | ||
108 | switch rrType { | ||
109 | case enums.GNS_TYPE_PKEY: | ||
110 | hdlr, err = NewPkeyHandler(rec, labels) | ||
111 | case enums.GNS_TYPE_GNS2DNS: | ||
112 | hdlr, err = NewGns2DnsHandler(rec, labels) | ||
113 | case enums.GNS_TYPE_BOX: | ||
114 | hdlr, err = NewBoxHandler(rec, labels) | ||
115 | case enums.GNS_TYPE_LEHO: | ||
116 | hdlr, err = NewLehoHandler(rec, labels) | ||
117 | } | ||
118 | if err != nil { | ||
119 | return nil, err | ||
120 | } | ||
121 | // store handler in list | ||
122 | hl.list[rrType] = hdlr | ||
123 | } | ||
124 | } | ||
125 | return hl, nil | ||
126 | } | ||
127 | |||
128 | // GetHandler returns a BlockHandler for the given key. If no block handler exists | ||
129 | // under the given name, a new one is created and stored in the list. The type of | ||
130 | // the new block handler is derived from the key value. | ||
131 | func (hl *BlockHandlerList) GetHandler(t int) BlockHandler { | ||
132 | // return handler for given key if it exists | ||
133 | if hdlr, ok := hl.list[t]; ok { | ||
134 | return hdlr | ||
135 | } | ||
136 | return nil | ||
137 | } | ||
138 | |||
139 | //---------------------------------------------------------------------- | ||
140 | // PKEY handler: Only one PKEY as sole record in a block | ||
141 | //---------------------------------------------------------------------- | ||
142 | |||
143 | // PkeyHandler implementing the BlockHandler interface | ||
144 | type PkeyHandler struct { | ||
145 | pkey *ed25519.PublicKey // Zone key | ||
146 | rec *message.GNSResourceRecord // associated recource record | ||
147 | } | ||
148 | |||
149 | // NewPkeyHandler returns a new BlockHandler instance | ||
150 | func NewPkeyHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) { | ||
151 | if int(rec.Type) != enums.GNS_TYPE_PKEY { | ||
152 | return nil, ErrInvalidRecordType | ||
153 | } | ||
154 | h := &PkeyHandler{ | ||
155 | pkey: nil, | ||
156 | } | ||
157 | if err := h.AddRecord(rec, labels); err != nil { | ||
158 | return nil, err | ||
159 | } | ||
160 | return h, nil | ||
161 | } | ||
162 | |||
163 | // AddRecord inserts a PKEY record into the handler. | ||
164 | func (h *PkeyHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error { | ||
165 | if int(rec.Type) != enums.GNS_TYPE_PKEY { | ||
166 | return ErrInvalidRecordType | ||
167 | } | ||
168 | // check for sole PKEY record in block | ||
169 | if h.pkey != nil { | ||
170 | return ErrInvalidPKEY | ||
171 | } | ||
172 | // check for sane key data | ||
173 | if len(rec.Data) != 32 { | ||
174 | return ErrInvalidPKEY | ||
175 | } | ||
176 | // set a PKEY handler | ||
177 | h.pkey = ed25519.NewPublicKeyFromBytes(rec.Data) | ||
178 | h.rec = rec | ||
179 | return nil | ||
180 | } | ||
181 | |||
182 | // TypeAction return a flag indicating how a resource record of a given type | ||
183 | // is to be treated (see BlockHandler interface) | ||
184 | func (h *PkeyHandler) TypeAction(t int) int { | ||
185 | // no other resource record type is not allowed | ||
186 | if t == enums.GNS_TYPE_PKEY { | ||
187 | return 1 | ||
188 | } | ||
189 | return -1 | ||
190 | } | ||
191 | |||
192 | // Records returns a list of RR of the given type associated with this handler | ||
193 | func (h *PkeyHandler) Records(kind RRTypeList) *GNSRecordSet { | ||
194 | rs := NewGNSRecordSet() | ||
195 | if kind.HasType(enums.GNS_TYPE_PKEY) { | ||
196 | rs.AddRecord(h.rec) | ||
197 | } | ||
198 | return rs | ||
199 | } | ||
200 | |||
201 | //---------------------------------------------------------------------- | ||
202 | // GNS2DNS handler | ||
203 | //---------------------------------------------------------------------- | ||
204 | |||
205 | // Gns2DnsHandler implementing the BlockHandler interface | ||
206 | type Gns2DnsHandler struct { | ||
207 | Name string // DNS query name | ||
208 | Servers []string // DNS servers to ask | ||
209 | recs []*message.GNSResourceRecord // list of rersource records | ||
210 | } | ||
211 | |||
212 | // NewGns2DnsHandler returns a new BlockHandler instance | ||
213 | func NewGns2DnsHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) { | ||
214 | if int(rec.Type) != enums.GNS_TYPE_GNS2DNS { | ||
215 | return nil, ErrInvalidRecordType | ||
216 | } | ||
217 | h := &Gns2DnsHandler{ | ||
218 | Name: "", | ||
219 | Servers: make([]string, 0), | ||
220 | recs: make([]*message.GNSResourceRecord, 0), | ||
221 | } | ||
222 | if err := h.AddRecord(rec, labels); err != nil { | ||
223 | return nil, err | ||
224 | } | ||
225 | return h, nil | ||
226 | } | ||
227 | |||
228 | // AddRecord inserts a GNS2DNS record into the handler. | ||
229 | func (h *Gns2DnsHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error { | ||
230 | if int(rec.Type) != enums.GNS_TYPE_GNS2DNS { | ||
231 | return ErrInvalidRecordType | ||
232 | } | ||
233 | logger.Printf(logger.DBG, "[gns] GNS2DNS data: %s\n", hex.EncodeToString(rec.Data)) | ||
234 | |||
235 | // extract list of names in DATA block: | ||
236 | next, dnsQuery := DNSNameFromBytes(rec.Data, 0) | ||
237 | dnsServer := string(rec.Data[next : len(rec.Data)-1]) | ||
238 | logger.Printf(logger.DBG, "[gns] GNS2DNS query '%s'@'%s'\n", dnsQuery, dnsServer) | ||
239 | if len(dnsServer) == 0 || len(dnsQuery) == 0 { | ||
240 | return ErrInvalidRecordBody | ||
241 | } | ||
242 | |||
243 | // check if all GNS2DNS records refer to the same query name | ||
244 | if len(h.Servers) == 0 { | ||
245 | h.Name = dnsQuery | ||
246 | } | ||
247 | if dnsQuery != h.Name { | ||
248 | return ErrInvalidRecordBody | ||
249 | } | ||
250 | h.Servers = append(h.Servers, dnsServer) | ||
251 | h.recs = append(h.recs, rec) | ||
252 | return nil | ||
253 | } | ||
254 | |||
255 | // TypeAction return a flag indicating how a resource record of a given type | ||
256 | // is to be treated (see BlockHandler interface) | ||
257 | func (h *Gns2DnsHandler) TypeAction(t int) int { | ||
258 | // anything goes... | ||
259 | return 1 | ||
260 | } | ||
261 | |||
262 | // Records returns a list of RR of the given type associated with this handler | ||
263 | func (h *Gns2DnsHandler) Records(kind RRTypeList) *GNSRecordSet { | ||
264 | rs := NewGNSRecordSet() | ||
265 | if kind.HasType(enums.GNS_TYPE_GNS2DNS) { | ||
266 | for _, rec := range h.recs { | ||
267 | rs.AddRecord(rec) | ||
268 | } | ||
269 | } | ||
270 | return rs | ||
271 | } | ||
272 | |||
273 | //---------------------------------------------------------------------- | ||
274 | // BOX handler | ||
275 | //---------------------------------------------------------------------- | ||
276 | |||
277 | // BoxHandler implementing the BlockHandler interface | ||
278 | type BoxHandler struct { | ||
279 | boxes map[string]*Box // map of found boxes | ||
280 | } | ||
281 | |||
282 | // NewBoxHandler returns a new BlockHandler instance | ||
283 | func NewBoxHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) { | ||
284 | if int(rec.Type) != enums.GNS_TYPE_BOX { | ||
285 | return nil, ErrInvalidRecordType | ||
286 | } | ||
287 | h := &BoxHandler{ | ||
288 | boxes: make(map[string]*Box), | ||
289 | } | ||
290 | if err := h.AddRecord(rec, labels); err != nil { | ||
291 | return nil, err | ||
292 | } | ||
293 | return h, nil | ||
294 | } | ||
295 | |||
296 | // AddRecord inserts a BOX record into the handler. | ||
297 | func (h *BoxHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error { | ||
298 | if int(rec.Type) != enums.GNS_TYPE_BOX { | ||
299 | return ErrInvalidRecordType | ||
300 | } | ||
301 | logger.Printf(logger.DBG, "[box-rr] for labels %v\n", labels) | ||
302 | // check if we need to process the BOX record: | ||
303 | // (1) only two remaining labels | ||
304 | if len(labels) != 2 { | ||
305 | return nil | ||
306 | } | ||
307 | // (2) remaining labels must start with '_' | ||
308 | if labels[0][0] != '_' || labels[1][0] != '_' { | ||
309 | return nil | ||
310 | } | ||
311 | // (3) check of "svc" and "proto" match values in the BOX | ||
312 | box := NewBox(rec) | ||
313 | if box.Matches(labels) { | ||
314 | logger.Println(logger.DBG, "[box-rr] MATCH -- adding record") | ||
315 | h.boxes[box.key] = box | ||
316 | } | ||
317 | return nil | ||
318 | } | ||
319 | |||
320 | // TypeAction return a flag indicating how a resource record of a given type | ||
321 | // is to be treated (see BlockHandler interface) | ||
322 | func (h *BoxHandler) TypeAction(t int) int { | ||
323 | // anything goes... | ||
324 | return 1 | ||
325 | } | ||
326 | |||
327 | // Records returns a list of RR of the given type associated with this handler | ||
328 | func (h *BoxHandler) Records(kind RRTypeList) *GNSRecordSet { | ||
329 | rs := NewGNSRecordSet() | ||
330 | for _, box := range h.boxes { | ||
331 | if kind.HasType(int(box.Type)) { | ||
332 | // valid box found: assemble new resource record. | ||
333 | rr := new(message.GNSResourceRecord) | ||
334 | rr.Expires = box.rec.Expires | ||
335 | rr.Flags = box.rec.Flags | ||
336 | rr.Type = box.Type | ||
337 | rr.Size = uint32(len(box.RR)) | ||
338 | rr.Data = box.RR | ||
339 | rs.AddRecord(rr) | ||
340 | } | ||
341 | } | ||
342 | return rs | ||
343 | } | ||
344 | |||
345 | //---------------------------------------------------------------------- | ||
346 | // LEHO handler | ||
347 | //---------------------------------------------------------------------- | ||
348 | |||
349 | // LehoHandler implementing the BlockHandler interface | ||
350 | type LehoHandler struct { | ||
351 | name string | ||
352 | rec *message.GNSResourceRecord | ||
353 | } | ||
354 | |||
355 | // NewLehoHandler returns a new BlockHandler instance | ||
356 | func NewLehoHandler(rec *message.GNSResourceRecord, labels []string) (BlockHandler, error) { | ||
357 | if int(rec.Type) != enums.GNS_TYPE_LEHO { | ||
358 | return nil, ErrInvalidRecordType | ||
359 | } | ||
360 | h := &LehoHandler{ | ||
361 | name: "", | ||
362 | } | ||
363 | if err := h.AddRecord(rec, labels); err != nil { | ||
364 | return nil, err | ||
365 | } | ||
366 | return h, nil | ||
367 | } | ||
368 | |||
369 | // AddRecord inserts a LEHO record into the handler. | ||
370 | func (h *LehoHandler) AddRecord(rec *message.GNSResourceRecord, labels []string) error { | ||
371 | if int(rec.Type) != enums.GNS_TYPE_LEHO { | ||
372 | return ErrInvalidRecordType | ||
373 | } | ||
374 | h.name = string(rec.Data) | ||
375 | h.rec = rec | ||
376 | return nil | ||
377 | } | ||
378 | |||
379 | // TypeAction return a flag indicating how a resource record of a given type | ||
380 | // is to be treated (see BlockHandler interface) | ||
381 | func (h *LehoHandler) TypeAction(t int) int { | ||
382 | // only A and AAAA records allowed beside LEHO | ||
383 | switch t { | ||
384 | case enums.GNS_TYPE_LEHO, enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA: | ||
385 | return 1 | ||
386 | default: | ||
387 | return -1 | ||
388 | } | ||
389 | } | ||
390 | |||
391 | // Records returns a list of RR of the given type associated with this handler | ||
392 | func (h *LehoHandler) Records(kind RRTypeList) *GNSRecordSet { | ||
393 | rs := NewGNSRecordSet() | ||
394 | if kind.HasType(enums.GNS_TYPE_LEHO) { | ||
395 | rs.AddRecord(h.rec) | ||
396 | } | ||
397 | return rs | ||
398 | } | ||
diff --git a/src/gnunet/service/gns/box.go b/src/gnunet/service/gns/box.go new file mode 100644 index 0000000..e2d3609 --- /dev/null +++ b/src/gnunet/service/gns/box.go | |||
@@ -0,0 +1,151 @@ | |||
1 | package gns | ||
2 | |||
3 | import ( | ||
4 | "encoding/hex" | ||
5 | "strconv" | ||
6 | "strings" | ||
7 | |||
8 | "gnunet/message" | ||
9 | |||
10 | "github.com/bfix/gospel/data" | ||
11 | "github.com/bfix/gospel/logger" | ||
12 | ) | ||
13 | |||
14 | // Box is an encapsulated RR for special names | ||
15 | type Box struct { | ||
16 | Proto uint16 `order:"big"` // Protcol identifier | ||
17 | Svc uint16 `order:"big"` // Service identifier | ||
18 | Type uint32 `order:"big"` // Type of embedded RR | ||
19 | RR []byte `size:"*"` // embedded RR | ||
20 | |||
21 | // transient attributes (not serialized) | ||
22 | key string // map key for box instance | ||
23 | rec *message.GNSResourceRecord // originating RR | ||
24 | } | ||
25 | |||
26 | // NewBox creates a new box instance from a BOX resource record. | ||
27 | func NewBox(rec *message.GNSResourceRecord) *Box { | ||
28 | b := new(Box) | ||
29 | if err := data.Unmarshal(b, rec.Data); err != nil { | ||
30 | logger.Printf(logger.ERROR, "[gns] Can't unmarshal BOX") | ||
31 | return nil | ||
32 | } | ||
33 | b.key = hex.EncodeToString(rec.Data[:8]) | ||
34 | b.rec = rec | ||
35 | return b | ||
36 | } | ||
37 | |||
38 | // Matches verifies that the remaining labels comply with the values | ||
39 | // in the BOX record. | ||
40 | func (b *Box) Matches(labels []string) bool { | ||
41 | // resolve protocol and service names | ||
42 | proto, protoName := GetProtocol(labels[0]) | ||
43 | svc, _ := GetService(labels[1], protoName) | ||
44 | // no match on invalid resolution | ||
45 | if proto == 0 || svc == 0 { | ||
46 | return false | ||
47 | } | ||
48 | // check for matching values in box | ||
49 | return proto == b.Proto && svc == b.Svc | ||
50 | } | ||
51 | |||
52 | //---------------------------------------------------------------------- | ||
53 | // helper functions | ||
54 | |||
55 | // list of handled protocols in BOX records | ||
56 | var protocols = map[string]int{ | ||
57 | "icmp": 1, | ||
58 | "igmp": 2, | ||
59 | "tcp": 6, | ||
60 | "udp": 17, | ||
61 | "ipv6-icmp": 58, | ||
62 | } | ||
63 | |||
64 | // GetProtocol returns the protocol number and name for a given name. The | ||
65 | // name can be an integer value (e.g. "_6" for "tcp") or a mnemonic name | ||
66 | // (e.g. like "_tcp"). | ||
67 | func GetProtocol(name string) (uint16, string) { | ||
68 | // check for required prefix | ||
69 | if name[0] != '_' { | ||
70 | return 0, "" | ||
71 | } | ||
72 | name = strings.ToLower(name[1:]) | ||
73 | |||
74 | // if label is an integer value it is the protocol number | ||
75 | if val, err := strconv.Atoi(name); err == nil { | ||
76 | // check for valid number (reverse protocol lookup) | ||
77 | for label, id := range protocols { | ||
78 | if id == val { | ||
79 | // return found entry | ||
80 | return uint16(val), label | ||
81 | } | ||
82 | } | ||
83 | // number out of range | ||
84 | return 0, "" | ||
85 | } | ||
86 | // try to resolve via protocol map | ||
87 | if id, ok := protocols[name]; ok { | ||
88 | return uint16(id), name | ||
89 | } | ||
90 | // resolution failed | ||
91 | return 0, "" | ||
92 | } | ||
93 | |||
94 | // list of services (per protocol) handled in BOX records | ||
95 | var services = map[string]map[string]int{ | ||
96 | "udp": { | ||
97 | "domain": 53, | ||
98 | }, | ||
99 | "tcp": { | ||
100 | "ftp": 21, | ||
101 | "ftps": 990, | ||
102 | "gopher": 70, | ||
103 | "http": 80, | ||
104 | "https": 443, | ||
105 | "imap2": 143, | ||
106 | "imap3": 220, | ||
107 | "imaps": 993, | ||
108 | "pop3": 110, | ||
109 | "pop3s": 995, | ||
110 | "smtp": 25, | ||
111 | "ssh": 22, | ||
112 | "telnet": 23, | ||
113 | }, | ||
114 | } | ||
115 | |||
116 | // GetService returns the port number and the name of a service (with given | ||
117 | // protocol). The name can be an integer value (e.g. "_443" for "https") or | ||
118 | // a mnemonic name (e.g. like "_https"). | ||
119 | func GetService(name, proto string) (uint16, string) { | ||
120 | // check for required prefix | ||
121 | if name[0] != '_' { | ||
122 | return 0, "" | ||
123 | } | ||
124 | name = strings.ToLower(name[1:]) | ||
125 | |||
126 | // get list of services for given protocol | ||
127 | svcs, ok := services[proto] | ||
128 | if !ok { | ||
129 | // no services available for this protocol | ||
130 | return 0, "" | ||
131 | } | ||
132 | |||
133 | // if label is an integer value it is the port number | ||
134 | if val, err := strconv.Atoi(name); err == nil { | ||
135 | // check for valid number (reverse service lookup) | ||
136 | for label, id := range svcs { | ||
137 | if id == val { | ||
138 | // return found entry | ||
139 | return uint16(val), label | ||
140 | } | ||
141 | } | ||
142 | // number out of range | ||
143 | return 0, "" | ||
144 | } | ||
145 | // try to resolve via services map | ||
146 | if id, ok := svcs[name]; ok { | ||
147 | return uint16(id), name | ||
148 | } | ||
149 | // resolution failed | ||
150 | return 0, "" | ||
151 | } | ||
diff --git a/src/gnunet/service/gns/dns.go b/src/gnunet/service/gns/dns.go index 2ebe331..fe138b0 100644 --- a/src/gnunet/service/gns/dns.go +++ b/src/gnunet/service/gns/dns.go | |||
@@ -47,7 +47,7 @@ func DNSNameFromBytes(b []byte, offset int) (int, string) { | |||
47 | 47 | ||
48 | // queryDNS resolves a name on a given nameserver and delivers all matching | 48 | // queryDNS resolves a name on a given nameserver and delivers all matching |
49 | // resource record (of type 'kind') to the result channel. | 49 | // resource record (of type 'kind') to the result channel. |
50 | func queryDNS(id int, name string, server net.IP, kind int, res chan *GNSRecordSet) { | 50 | func queryDNS(id int, name string, server net.IP, kind RRTypeList, res chan *GNSRecordSet) { |
51 | logger.Printf(logger.DBG, "[dns][%d] Starting query for '%s' on '%s'...\n", id, name, server.String()) | 51 | logger.Printf(logger.DBG, "[dns][%d] Starting query for '%s' on '%s'...\n", id, name, server.String()) |
52 | 52 | ||
53 | // assemble query | 53 | // assemble query |
@@ -91,27 +91,32 @@ func queryDNS(id int, name string, server net.IP, kind int, res chan *GNSRecordS | |||
91 | } | 91 | } |
92 | set := NewGNSRecordSet() | 92 | set := NewGNSRecordSet() |
93 | for _, record := range in.Answer { | 93 | for _, record := range in.Answer { |
94 | // create a new GNS resource record | 94 | // check if answer record is of requested type |
95 | rr := new(message.GNSResourceRecord) | 95 | if kind.HasType(int(record.Header().Rrtype)) { |
96 | rr.Expires = util.AbsoluteTimeNever() | 96 | // get wire-format of resource record |
97 | rr.Flags = 0 | 97 | buf := make([]byte, 2048) |
98 | rr.Type = uint32(record.Header().Rrtype) | 98 | n, err := dns.PackRR(record, buf, 0, nil, false) |
99 | rr.Size = uint32(record.Header().Rdlength) | 99 | if err != nil { |
100 | rr.Data = make([]byte, rr.Size) | 100 | logger.Printf(logger.WARN, "[dns][%d] Failed to get RR data for %s\n", id, err.Error()) |
101 | continue | ||
102 | } | ||
101 | 103 | ||
102 | // get wire-format of resource record | 104 | // create a new GNS resource record |
103 | buf := make([]byte, 2048) | 105 | rr := new(message.GNSResourceRecord) |
104 | n, err := dns.PackRR(record, buf, 0, nil, false) | 106 | expires := time.Now().Add(time.Duration(record.Header().Ttl) * time.Second) |
105 | if err != nil { | 107 | rr.Expires = util.NewAbsoluteTime(expires) |
106 | logger.Printf(logger.WARN, "[dns][%d] Failed to get RR data for %s\n", id, err.Error()) | 108 | rr.Flags = 0 |
107 | continue | 109 | rr.Type = uint32(record.Header().Rrtype) |
108 | } | 110 | rr.Size = uint32(record.Header().Rdlength) |
109 | if n < int(rr.Size) { | 111 | rr.Data = make([]byte, rr.Size) |
110 | logger.Printf(logger.WARN, "[dns][%d] Nit enough data in RR (%d != %d)\n", id, n, rr.Size) | 112 | |
111 | continue | 113 | if n < int(rr.Size) { |
114 | logger.Printf(logger.WARN, "[dns][%d] Not enough data in RR (%d != %d)\n", id, n, rr.Size) | ||
115 | continue | ||
116 | } | ||
117 | copy(rr.Data, buf[n-int(rr.Size):]) | ||
118 | set.AddRecord(rr) | ||
112 | } | 119 | } |
113 | copy(rr.Data, buf[n-int(rr.Size):]) | ||
114 | set.AddRecord(rr) | ||
115 | } | 120 | } |
116 | logger.Printf(logger.WARN, "[dns][%d] %d resource records extracted from response (%d/5).\n", id, set.Count, retry+1) | 121 | logger.Printf(logger.WARN, "[dns][%d] %d resource records extracted from response (%d/5).\n", id, set.Count, retry+1) |
117 | res <- set | 122 | res <- set |
@@ -124,7 +129,7 @@ func queryDNS(id int, name string, server net.IP, kind int, res chan *GNSRecordS | |||
124 | // ResolveDNS resolves a name in DNS. Multiple DNS servers are queried in | 129 | // ResolveDNS resolves a name in DNS. Multiple DNS servers are queried in |
125 | // parallel; the first result delivered by any of the servers is returned | 130 | // parallel; the first result delivered by any of the servers is returned |
126 | // as the result list of matching resource records. | 131 | // as the result list of matching resource records. |
127 | func (gns *GNSModule) ResolveDNS(name string, servers []string, kind int, pkey *ed25519.PublicKey) (set *GNSRecordSet, err error) { | 132 | func (gns *GNSModule) ResolveDNS(name string, servers []string, kind RRTypeList, pkey *ed25519.PublicKey) (set *GNSRecordSet, err error) { |
128 | logger.Printf(logger.DBG, "[dns] Resolution of '%s' starting...\n", name) | 133 | logger.Printf(logger.DBG, "[dns] Resolution of '%s' starting...\n", name) |
129 | 134 | ||
130 | // start DNS queries concurrently | 135 | // start DNS queries concurrently |
@@ -133,20 +138,22 @@ func (gns *GNSModule) ResolveDNS(name string, servers []string, kind int, pkey * | |||
133 | for idx, srv := range servers { | 138 | for idx, srv := range servers { |
134 | // check if srv is an IPv4/IPv6 address | 139 | // check if srv is an IPv4/IPv6 address |
135 | addr := net.ParseIP(srv) | 140 | addr := net.ParseIP(srv) |
141 | logger.Printf(logger.DBG, "ParseIP('%s', len=%d) --> %v\n", srv, len(srv), addr) | ||
136 | if addr == nil { | 142 | if addr == nil { |
143 | query := NewRRTypeList(enums.GNS_TYPE_DNS_A, enums.GNS_TYPE_DNS_AAAA) | ||
137 | // no; resolve server name in GNS | 144 | // no; resolve server name in GNS |
138 | if strings.HasSuffix(srv, ".+") { | 145 | if strings.HasSuffix(srv, ".+") { |
139 | // resolve server name relative to current zone | 146 | // resolve server name relative to current zone |
140 | zone := util.EncodeBinaryToString(pkey.Bytes()) | 147 | zone := util.EncodeBinaryToString(pkey.Bytes()) |
141 | srv = strings.TrimSuffix(srv, ".+") | 148 | srv = strings.TrimSuffix(srv, ".+") |
142 | set, err = gns.Resolve(srv, pkey, enums.GNS_TYPE_ANY, enums.GNS_LO_DEFAULT) | 149 | set, err = gns.Resolve(srv, pkey, query, enums.GNS_LO_DEFAULT) |
143 | if err != nil { | 150 | if err != nil { |
144 | logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s' in '%s'\n", srv, zone) | 151 | logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s' in '%s'\n", srv, zone) |
145 | continue | 152 | continue |
146 | } | 153 | } |
147 | } else { | 154 | } else { |
148 | // resolve absolute GNS name (MUST end in a PKEY) | 155 | // resolve absolute GNS name (name MUST end in a PKEY) |
149 | set, err = gns.Resolve(srv, nil, enums.GNS_TYPE_ANY, enums.GNS_LO_DEFAULT) | 156 | set, err = gns.Resolve(srv, nil, query, enums.GNS_LO_DEFAULT) |
150 | if err != nil { | 157 | if err != nil { |
151 | logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s'\n", srv) | 158 | logger.Printf(logger.ERROR, "[dns] Can't resolve NS server '%s'\n", srv) |
152 | continue | 159 | continue |
@@ -158,11 +165,17 @@ func (gns *GNSModule) ResolveDNS(name string, servers []string, kind int, pkey * | |||
158 | switch int(rec.Type) { | 165 | switch int(rec.Type) { |
159 | case enums.GNS_TYPE_DNS_AAAA: | 166 | case enums.GNS_TYPE_DNS_AAAA: |
160 | addr = net.IP(rec.Data) | 167 | addr = net.IP(rec.Data) |
168 | // we prefer IPv6 | ||
161 | break rec_loop | 169 | break rec_loop |
162 | case enums.GNS_TYPE_DNS_A: | 170 | case enums.GNS_TYPE_DNS_A: |
163 | addr = net.IP(rec.Data) | 171 | addr = net.IP(rec.Data) |
164 | } | 172 | } |
165 | } | 173 | } |
174 | // check if we have an IP address available | ||
175 | if addr == nil { | ||
176 | logger.Printf(logger.WARN, "[dns] No IP address for nameserver in GNS") | ||
177 | continue | ||
178 | } | ||
166 | } | 179 | } |
167 | // query DNS concurrently | 180 | // query DNS concurrently |
168 | go queryDNS(idx, name, addr, kind, res) | 181 | go queryDNS(idx, name, addr, kind, res) |
diff --git a/src/gnunet/service/gns/module.go b/src/gnunet/service/gns/module.go index e4dc5fb..3e7bd18 100644 --- a/src/gnunet/service/gns/module.go +++ b/src/gnunet/service/gns/module.go | |||
@@ -1,7 +1,6 @@ | |||
1 | package gns | 1 | package gns |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/hex" | ||
5 | "fmt" | 4 | "fmt" |
6 | "strings" | 5 | "strings" |
7 | 6 | ||
@@ -55,82 +54,39 @@ func NewQuery(pkey *ed25519.PublicKey, label string) *Query { | |||
55 | } | 54 | } |
56 | 55 | ||
57 | //---------------------------------------------------------------------- | 56 | //---------------------------------------------------------------------- |
58 | // GNS blocks with special types (PKEY, GNS2DNS) require special | ||
59 | // treatment with respect to other resource records with different types | ||
60 | // in the same block. Usually only certain other types (or not at all) | ||
61 | // are allowed and the allowed ones are required to deliver a consistent | ||
62 | // list of resulting resource records passed back to the caller. | ||
63 | //---------------------------------------------------------------------- | ||
64 | |||
65 | // BlockHandler interface. | ||
66 | type BlockHandler interface { | ||
67 | // TypeAction returns a flag indicating how a resource record of a | ||
68 | // given type is to be treated: | ||
69 | // = -1: Record is not allowed (terminates lookup with an error) | ||
70 | // = 0: Record is allowed but will be ignored | ||
71 | // = 1: Record is allowed and will be processed | ||
72 | TypeAction(int) int | ||
73 | } | ||
74 | |||
75 | // Gns2DnsHandler implementing the BlockHandler interface | ||
76 | type Gns2DnsHandler struct { | ||
77 | Name string | ||
78 | Servers []string | ||
79 | } | ||
80 | |||
81 | // NewGns2DnsHandler returns a new BlockHandler instance | ||
82 | func NewGns2DnsHandler() *Gns2DnsHandler { | ||
83 | return &Gns2DnsHandler{ | ||
84 | Name: "", | ||
85 | Servers: make([]string, 0), | ||
86 | } | ||
87 | } | ||
88 | |||
89 | // TypeAction return a flag indicating how a resource record of a given type | ||
90 | // is to be treated (see RecordMaster interface) | ||
91 | func (m *Gns2DnsHandler) TypeAction(t int) int { | ||
92 | // only process other GNS2DNS records | ||
93 | if t == enums.GNS_TYPE_GNS2DNS { | ||
94 | return 1 | ||
95 | } | ||
96 | // skip everything else | ||
97 | return 0 | ||
98 | } | ||
99 | |||
100 | // AddRequest adds the DNS request for "name" at "server" to the list | ||
101 | // of requests. All GNS2DNS records must query for the same name | ||
102 | func (m *Gns2DnsHandler) AddRequest(name, server string) bool { | ||
103 | if len(m.Servers) == 0 { | ||
104 | m.Name = name | ||
105 | } | ||
106 | if name != m.Name { | ||
107 | return false | ||
108 | } | ||
109 | m.Servers = append(m.Servers, server) | ||
110 | return true | ||
111 | } | ||
112 | |||
113 | //---------------------------------------------------------------------- | ||
114 | // The GNS module (recursively) resolves GNS names: | 57 | // The GNS module (recursively) resolves GNS names: |
115 | // Resolves DNS-like names (e.g. "minecraft.servers.bob.games") to the | 58 | // Resolves DNS-like names (e.g. "minecraft.servers.bob.games"; a name is |
116 | // requested resource records (RRs). In short, the resolution process | 59 | // a list of labels with '.' as separator) to the requested resource |
117 | // works as follows: | 60 | // records (RRs). In short, the resolution process works as follows: |
118 | // | 61 | // |
119 | // Resolve(name): | 62 | // Resolve(name): |
120 | // -------------- | 63 | // -------------- |
121 | // (1) split the full name into elements in reverse order: names[] | 64 | // (1) split the name ('.' as separator) into labels in reverse order: labels[] |
122 | // (2) Resolve first element (root zone, right-most name part, name[0]) to | 65 | // (2) Resolve first label (= root zone, right-most name part, labels[0]) to |
123 | // a zone public key PKEY: | 66 | // a zone public key PKEY: |
124 | // (a) the name is a string representation of a public key -> (3) | 67 | // (a) the label is a string representation of a public key -> (3) |
125 | // (b) the zone key for the name is stored in the config file -> (3) | 68 | // (b) the zone key for the label is stored in the config file -> (3) |
126 | // (c) a local zone with that given name -> (3) | 69 | // (c) a local zone with that given label -> (3) |
127 | // (d) ERROR: "Unknown root zone" | 70 | // (d) ERROR: "Unknown root zone" |
128 | // (3) names = names[1:] // remove first element | 71 | // (3) labels = labels[1:] |
129 | // block = Lookup (PKEY, names[0]): | 72 | // records = Resolve (labels[0], PKEY) |
130 | // (a) If last element of namess: -> (4) | 73 | // If last label in name: -> (5) |
131 | // (b) block is PKEY record: | 74 | // (4) for all rec in records: |
132 | // PKEY <- block, --> (3) | 75 | // (a) if rec is a PKEY record: |
133 | // (4) return block: it is the responsibility of the caller to assemble | 76 | // PKEY <- record, --> (3) |
77 | // (b) if rec is a GNS2DNS record: | ||
78 | // delegate to DNS to resolve rest of name -> (5) | ||
79 | // (c) if rec is BOX record: | ||
80 | // if rest of name is pattern "_service._proto" and matches | ||
81 | // the values in the BOX: | ||
82 | // Replace records with resource record from BOX -> (5) | ||
83 | // (d) if rec is CNAME record: | ||
84 | // if no remaining labels: | ||
85 | // if requested types include CNAME -> (5) | ||
86 | // if | ||
87 | // resolution failed: name not completely processed and no zone available | ||
88 | // | ||
89 | // (5) return records: it is the responsibility of the caller to assemble | ||
134 | // the desired result from block data (e.g. filter for requested | 90 | // the desired result from block data (e.g. filter for requested |
135 | // resource record types). | 91 | // resource record types). |
136 | //---------------------------------------------------------------------- | 92 | //---------------------------------------------------------------------- |
@@ -145,10 +101,10 @@ type GNSModule struct { | |||
145 | GetLocalZone func(name string) (*ed25519.PublicKey, error) | 101 | GetLocalZone func(name string) (*ed25519.PublicKey, error) |
146 | } | 102 | } |
147 | 103 | ||
148 | // Resolve a GNS name with multiple elements, If pkey is not nil, the name | 104 | // Resolve a GNS name with multiple labels. If pkey is not nil, the name |
149 | // is interpreted as "relative to current zone". | 105 | // is interpreted as "relative to current zone". |
150 | func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind int, mode int) (set *GNSRecordSet, err error) { | 106 | func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind RRTypeList, mode int) (set *GNSRecordSet, err error) { |
151 | // get the name elements in reverse order | 107 | // get the labels in reverse order |
152 | names := util.ReverseStringList(strings.Split(path, ".")) | 108 | names := util.ReverseStringList(strings.Split(path, ".")) |
153 | logger.Printf(logger.DBG, "[gns] Resolver called for %v\n", names) | 109 | logger.Printf(logger.DBG, "[gns] Resolver called for %v\n", names) |
154 | 110 | ||
@@ -161,8 +117,8 @@ func (gns *GNSModule) Resolve(path string, pkey *ed25519.PublicKey, kind int, mo | |||
161 | return gns.ResolveAbsolute(names, kind, mode) | 117 | return gns.ResolveAbsolute(names, kind, mode) |
162 | } | 118 | } |
163 | 119 | ||
164 | // Resolve a fully qualified GNS absolute name (with multiple levels). | 120 | // Resolve a fully qualified GNS absolute name (with multiple labels). |
165 | func (gns *GNSModule) ResolveAbsolute(names []string, kind int, mode int) (set *GNSRecordSet, err error) { | 121 | func (gns *GNSModule) ResolveAbsolute(labels []string, kind RRTypeList, mode int) (set *GNSRecordSet, err error) { |
166 | // get the root zone key for the TLD | 122 | // get the root zone key for the TLD |
167 | var ( | 123 | var ( |
168 | pkey *ed25519.PublicKey | 124 | pkey *ed25519.PublicKey |
@@ -170,40 +126,43 @@ func (gns *GNSModule) ResolveAbsolute(names []string, kind int, mode int) (set * | |||
170 | ) | 126 | ) |
171 | for { | 127 | for { |
172 | // (1) check if TLD is a public key string | 128 | // (1) check if TLD is a public key string |
173 | if len(names[0]) == 52 { | 129 | if len(labels[0]) == 52 { |
174 | if data, err = util.DecodeStringToBinary(names[0], 32); err == nil { | 130 | if data, err = util.DecodeStringToBinary(labels[0], 32); err == nil { |
175 | if pkey = ed25519.NewPublicKeyFromBytes(data); pkey != nil { | 131 | if pkey = ed25519.NewPublicKeyFromBytes(data); pkey != nil { |
176 | break | 132 | break |
177 | } | 133 | } |
178 | } | 134 | } |
179 | } | 135 | } |
180 | // (2) check if TLD is in our local config | 136 | // (2) check if TLD is in our local config |
181 | if pkey = config.Cfg.GNS.GetRootZoneKey(names[0]); pkey != nil { | 137 | if pkey = config.Cfg.GNS.GetRootZoneKey(labels[0]); pkey != nil { |
182 | break | 138 | break |
183 | } | 139 | } |
184 | // (3) check if TLD is one of our identities | 140 | // (3) check if TLD is one of our identities |
185 | if pkey, err = gns.GetLocalZone(names[0]); err == nil { | 141 | if pkey, err = gns.GetLocalZone(labels[0]); err == nil { |
186 | break | 142 | break |
187 | } | 143 | } |
188 | // (4) we can't resolve this TLD | 144 | // (4) we can't resolve this TLD |
189 | return nil, ErrUnknownTLD | 145 | return nil, ErrUnknownTLD |
190 | } | 146 | } |
191 | // continue with resolution relative to a zone. | 147 | // continue with resolution relative to a zone. |
192 | return gns.ResolveRelative(names[1:], pkey, kind, mode) | 148 | return gns.ResolveRelative(labels[1:], pkey, kind, mode) |
193 | } | 149 | } |
194 | 150 | ||
195 | // Resolve relative path (to a given zone) recursively by processing simple | 151 | // Resolve relative path (to a given zone) recursively by processing simple |
196 | // (PKEY,Label) lookups in sequence and handle intermediate GNS record types | 152 | // (PKEY,Label) lookups in sequence and handle intermediate GNS record types |
197 | func (gns *GNSModule) ResolveRelative(names []string, pkey *ed25519.PublicKey, kind int, mode int) (set *GNSRecordSet, err error) { | 153 | func (gns *GNSModule) ResolveRelative(labels []string, pkey *ed25519.PublicKey, kind RRTypeList, mode int) (set *GNSRecordSet, err error) { |
198 | // Process all names in sequence | 154 | // Process all names in sequence |
199 | var records []*message.GNSResourceRecord | 155 | var ( |
156 | records []*message.GNSResourceRecord // final resource records from resolution | ||
157 | hdlrs *BlockHandlerList // list of block handlers in final step | ||
158 | ) | ||
200 | name_loop: | 159 | name_loop: |
201 | for ; len(names) > 0; names = names[1:] { | 160 | for ; len(labels) > 0; labels = labels[1:] { |
202 | logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in '%s'\n", names[0], util.EncodeBinaryToString(pkey.Bytes())) | 161 | logger.Printf(logger.DBG, "[gns] ResolveRelative '%s' in '%s'\n", labels[0], util.EncodeBinaryToString(pkey.Bytes())) |
203 | 162 | ||
204 | // resolve next level | 163 | // resolve next level |
205 | var block *GNSBlock | 164 | var block *GNSBlock |
206 | if block, err = gns.Lookup(pkey, names[0], mode == enums.GNS_LO_DEFAULT); err != nil { | 165 | if block, err = gns.Lookup(pkey, labels[0], mode == enums.GNS_LO_DEFAULT); err != nil { |
207 | // failed to resolve name | 166 | // failed to resolve name |
208 | return | 167 | return |
209 | } | 168 | } |
@@ -213,94 +172,64 @@ name_loop: | |||
213 | } | 172 | } |
214 | // post-process block by inspecting contained resource records for | 173 | // post-process block by inspecting contained resource records for |
215 | // special GNS types | 174 | // special GNS types |
216 | var hdlr BlockHandler | ||
217 | if records, err = block.Records(); err != nil { | 175 | if records, err = block.Records(); err != nil { |
218 | return | 176 | return |
219 | } | 177 | } |
220 | for _, rec := range records { | 178 | // assemble a list of block handlers for this block: if multiple |
221 | // let a block handler decide how to handle records | 179 | // block handlers are present, they are consistent with all block |
222 | if hdlr != nil { | 180 | // records. |
223 | switch hdlr.TypeAction(int(rec.Type)) { | 181 | if hdlrs, err = NewBlockHandlerList(records, labels[1:]); err != nil { |
224 | case -1: | 182 | // conflicting block handler records found: terminate with error. |
225 | // No records of this type allowed in block | 183 | // (N.B.: The BlockHandlerList class executes the logic which mix |
226 | err = ErrInvalidRecordType | 184 | // of resource records in a single block is considered valid.) |
227 | return | 185 | return |
228 | case 0: | 186 | } |
229 | // records of this type are simply ignored | ||
230 | continue | ||
231 | case 1: | ||
232 | // process record of this type | ||
233 | } | ||
234 | } | ||
235 | switch int(rec.Type) { | ||
236 | //---------------------------------------------------------- | ||
237 | case enums.GNS_TYPE_PKEY: | ||
238 | // check for single RR and sane key data | ||
239 | if len(rec.Data) != 32 || len(records) > 1 { | ||
240 | err = ErrInvalidPKEY | ||
241 | return | ||
242 | } | ||
243 | // set new PKEY and continue resolution | ||
244 | pkey = ed25519.NewPublicKeyFromBytes(rec.Data) | ||
245 | continue name_loop | ||
246 | 187 | ||
247 | //---------------------------------------------------------- | 188 | //-------------------------------------------------------------- |
248 | case enums.GNS_TYPE_GNS2DNS: | 189 | // handle special block cases in priority order: |
249 | // get the master controlling this block; create a new | 190 | //-------------------------------------------------------------- |
250 | // one if necessary | 191 | |
251 | var inst *Gns2DnsHandler | 192 | if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_PKEY); hdlr != nil { |
252 | if hdlr == nil { | 193 | // (1) PKEY record: |
253 | inst = NewGns2DnsHandler() | 194 | inst := hdlr.(*PkeyHandler) |
254 | hdlr = inst | 195 | // if labels are pending, set new zone and continue resolution |
255 | } else { | 196 | if len(labels) > 1 { |
256 | inst = hdlr.(*Gns2DnsHandler) | 197 | pkey = inst.pkey |
257 | } | 198 | continue name_loop |
258 | // extract list of names in DATA block: | ||
259 | logger.Printf(logger.DBG, "[gns] GNS2DNS data: %s\n", hex.EncodeToString(rec.Data)) | ||
260 | var dnsNames []string | ||
261 | for pos := 0; ; { | ||
262 | next, name := DNSNameFromBytes(rec.Data, pos) | ||
263 | if len(name) == 0 { | ||
264 | break | ||
265 | } | ||
266 | dnsNames = append(dnsNames, name) | ||
267 | pos = next | ||
268 | } | ||
269 | logger.Printf(logger.DBG, "[gns] GNS2DNS params: %v\n", dnsNames) | ||
270 | if len(dnsNames) != 2 { | ||
271 | err = ErrInvalidRecordBody | ||
272 | return | ||
273 | } | ||
274 | // Add to collection of requests | ||
275 | logger.Printf(logger.DBG, "[gns] GNS2DNS: query for '%s' on '%s'\n", dnsNames[0], dnsNames[1]) | ||
276 | if !inst.AddRequest(dnsNames[0], dnsNames[1]) { | ||
277 | err = ErrInvalidRecordBody | ||
278 | return | ||
279 | } | ||
280 | } | 199 | } |
281 | } | 200 | } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_GNS2DNS); hdlr != nil { |
282 | // handle special block cases | 201 | // (2) GNS2DNS records: delegate resolution to DNS |
283 | if hdlr != nil { | 202 | inst := hdlr.(*Gns2DnsHandler) |
284 | switch inst := hdlr.(type) { | 203 | // we need to handle delegation to DNS: returns a list of found |
285 | case *Gns2DnsHandler: | 204 | // resource records in DNS (filter by 'kind') |
286 | // we need to handle delegation to DNS: returns a list of found | 205 | lbls := strings.Join(util.ReverseStringList(labels[1:]), ".") |
287 | // resource records in DNS (filter by 'kind') | 206 | if len(lbls) > 0 { |
288 | fqdn := strings.Join(util.ReverseStringList(names[1:]), ".") + "." + inst.Name | 207 | lbls += "." |
289 | if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind, pkey); err != nil { | 208 | } |
290 | logger.Println(logger.ERROR, "[gns] GNS2DNS resilution failed.") | 209 | fqdn := lbls + inst.Name |
291 | return | 210 | if set, err = gns.ResolveDNS(fqdn, inst.Servers, kind, pkey); err != nil { |
292 | } | 211 | logger.Println(logger.ERROR, "[gns] GNS2DNS resolution failed.") |
293 | // we are done with resolution; pass on records to caller | 212 | return |
294 | records = set.Records | 213 | } |
214 | // we are done with resolution; pass on records to caller | ||
215 | records = set.Records | ||
216 | break name_loop | ||
217 | } else if hdlr := hdlrs.GetHandler(enums.GNS_TYPE_BOX); hdlr != nil { | ||
218 | // (3) BOX records: | ||
219 | inst := hdlr.(*BoxHandler) | ||
220 | new_records := inst.Records(kind).Records | ||
221 | if len(new_records) > 0 { | ||
222 | records = new_records | ||
295 | break name_loop | 223 | break name_loop |
296 | } | 224 | } |
297 | } | 225 | } |
298 | } | 226 | } |
299 | // Assemble resulting resource record set | 227 | // Assemble resulting resource record set by filtering for requested types. |
228 | // Records might get transformed by active block handlers. | ||
300 | set = NewGNSRecordSet() | 229 | set = NewGNSRecordSet() |
301 | for _, rec := range records { | 230 | for _, rec := range records { |
302 | // is this the record type we are looking for? | 231 | // is this the record type we are looking for? |
303 | if kind == enums.GNS_TYPE_ANY || int(rec.Type) == kind { | 232 | if kind.HasType(int(rec.Type)) { |
304 | // add it to the result | 233 | // add it to the result |
305 | set.AddRecord(rec) | 234 | set.AddRecord(rec) |
306 | } | 235 | } |
@@ -321,7 +250,6 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote bool) | |||
321 | return | 250 | return |
322 | } | 251 | } |
323 | if block == nil { | 252 | if block == nil { |
324 | logger.Println(logger.DBG, "[gns] local Lookup: no block found") | ||
325 | if remote { | 253 | if remote { |
326 | // get the block from a remote lookup | 254 | // get the block from a remote lookup |
327 | if block, err = gns.LookupRemote(query); err != nil || block == nil { | 255 | if block, err = gns.LookupRemote(query); err != nil || block == nil { |
@@ -330,12 +258,15 @@ func (gns *GNSModule) Lookup(pkey *ed25519.PublicKey, label string, remote bool) | |||
330 | block = nil | 258 | block = nil |
331 | } else { | 259 | } else { |
332 | logger.Println(logger.DBG, "[gns] remote Lookup: no block found") | 260 | logger.Println(logger.DBG, "[gns] remote Lookup: no block found") |
261 | err = fmt.Errorf("No block found") | ||
333 | } | 262 | } |
334 | // lookup fails completely -- no result | 263 | // lookup fails completely -- no result |
335 | return | 264 | return |
336 | } | 265 | } |
337 | // store RRs from remote locally. | 266 | // store RRs from remote locally. |
338 | gns.StoreLocal(query, block) | 267 | gns.StoreLocal(query, block) |
268 | } else { | ||
269 | err = fmt.Errorf("No block found") | ||
339 | } | 270 | } |
340 | } | 271 | } |
341 | return | 272 | return |
diff --git a/src/gnunet/service/gns/service.go b/src/gnunet/service/gns/service.go index 852f513..dd516ff 100644 --- a/src/gnunet/service/gns/service.go +++ b/src/gnunet/service/gns/service.go | |||
@@ -4,9 +4,6 @@ import ( | |||
4 | "encoding/hex" | 4 | "encoding/hex" |
5 | "io" | 5 | "io" |
6 | 6 | ||
7 | "github.com/bfix/gospel/crypto/ed25519" | ||
8 | "github.com/bfix/gospel/data" | ||
9 | "github.com/bfix/gospel/logger" | ||
10 | "gnunet/config" | 7 | "gnunet/config" |
11 | "gnunet/crypto" | 8 | "gnunet/crypto" |
12 | "gnunet/enums" | 9 | "gnunet/enums" |
@@ -14,6 +11,10 @@ import ( | |||
14 | "gnunet/service" | 11 | "gnunet/service" |
15 | "gnunet/transport" | 12 | "gnunet/transport" |
16 | "gnunet/util" | 13 | "gnunet/util" |
14 | |||
15 | "github.com/bfix/gospel/crypto/ed25519" | ||
16 | "github.com/bfix/gospel/data" | ||
17 | "github.com/bfix/gospel/logger" | ||
17 | ) | 18 | ) |
18 | 19 | ||
19 | //---------------------------------------------------------------------- | 20 | //---------------------------------------------------------------------- |
@@ -77,7 +78,8 @@ func (s *GNSService) ServeClient(mc *transport.MsgChannel) { | |||
77 | // access to the message channel to send responses) | 78 | // access to the message channel to send responses) |
78 | pkey := ed25519.NewPublicKeyFromBytes(m.Zone) | 79 | pkey := ed25519.NewPublicKeyFromBytes(m.Zone) |
79 | label := m.GetName() | 80 | label := m.GetName() |
80 | recset, err := s.Resolve(label, pkey, int(m.Type), int(m.Options)) | 81 | kind := NewRRTypeList(int(m.Type)) |
82 | recset, err := s.Resolve(label, pkey, kind, int(m.Options)) | ||
81 | if err != nil { | 83 | if err != nil { |
82 | logger.Printf(logger.ERROR, "[gns] Failed to lookup block: %s\n", err.Error()) | 84 | logger.Printf(logger.ERROR, "[gns] Failed to lookup block: %s\n", err.Error()) |
83 | break | 85 | break |
@@ -146,7 +148,7 @@ func (s *GNSService) LookupNamecache(query *Query) (block *GNSBlock, err error) | |||
146 | break | 148 | break |
147 | } | 149 | } |
148 | // check if block was found | 150 | // check if block was found |
149 | if len(m.EncData) == 0 { | 151 | if len(m.EncData) == 0 || util.IsNull(m.EncData) { |
150 | logger.Println(logger.DBG, "[gns] block not found in namecache") | 152 | logger.Println(logger.DBG, "[gns] block not found in namecache") |
151 | break | 153 | break |
152 | } | 154 | } |
diff --git a/src/gnunet/service/service.go b/src/gnunet/service/service.go index 5b44d47..6aab226 100644 --- a/src/gnunet/service/service.go +++ b/src/gnunet/service/service.go | |||
@@ -3,8 +3,9 @@ package service | |||
3 | import ( | 3 | import ( |
4 | "fmt" | 4 | "fmt" |
5 | 5 | ||
6 | "github.com/bfix/gospel/logger" | ||
7 | "gnunet/transport" | 6 | "gnunet/transport" |
7 | |||
8 | "github.com/bfix/gospel/logger" | ||
8 | ) | 9 | ) |
9 | 10 | ||
10 | // Service is an interface for GNUnet services. Every service has one channel | 11 | // Service is an interface for GNUnet services. Every service has one channel |
@@ -48,7 +49,7 @@ func (si *ServiceImpl) Start(spec string) (err error) { | |||
48 | } | 49 | } |
49 | 50 | ||
50 | // start channel server | 51 | // start channel server |
51 | logger.Printf(logger.DBG, "[%s] Service starting.\n", si.name) | 52 | logger.Printf(logger.INFO, "[%s] Service starting.\n", si.name) |
52 | if si.srvc, err = transport.NewChannelServer(spec, si.hdlr); err != nil { | 53 | if si.srvc, err = transport.NewChannelServer(spec, si.hdlr); err != nil { |
53 | return | 54 | return |
54 | } | 55 | } |
@@ -61,19 +62,19 @@ func (si *ServiceImpl) Start(spec string) (err error) { | |||
61 | select { | 62 | select { |
62 | case in := <-si.hdlr: | 63 | case in := <-si.hdlr: |
63 | if in == nil { | 64 | if in == nil { |
64 | logger.Printf(logger.DBG, "[%s] Listener terminated.\n", si.name) | 65 | logger.Printf(logger.INFO, "[%s] Listener terminated.\n", si.name) |
65 | break loop | 66 | break loop |
66 | } | 67 | } |
67 | switch ch := in.(type) { | 68 | switch ch := in.(type) { |
68 | case transport.Channel: | 69 | case transport.Channel: |
69 | logger.Printf(logger.DBG, "[%s] Client connected.\n", si.name) | 70 | logger.Printf(logger.INFO, "[%s] Client connected.\n", si.name) |
70 | go si.impl.ServeClient(transport.NewMsgChannel(ch)) | 71 | go si.impl.ServeClient(transport.NewMsgChannel(ch)) |
71 | } | 72 | } |
72 | case <-si.ctrl: | 73 | case <-si.ctrl: |
73 | break loop | 74 | break loop |
74 | } | 75 | } |
75 | } | 76 | } |
76 | logger.Printf(logger.DBG, "[%s] Service closing.\n", si.name) | 77 | logger.Printf(logger.INFO, "[%s] Service closing.\n", si.name) |
77 | si.srvc.Close() | 78 | si.srvc.Close() |
78 | si.running = false | 79 | si.running = false |
79 | }() | 80 | }() |
@@ -89,7 +90,7 @@ func (si *ServiceImpl) Stop() error { | |||
89 | } | 90 | } |
90 | si.running = false | 91 | si.running = false |
91 | si.ctrl <- true | 92 | si.ctrl <- true |
92 | logger.Printf(logger.DBG, "[%s] Service terminating.\n", si.name) | 93 | logger.Printf(logger.INFO, "[%s] Service terminating.\n", si.name) |
93 | 94 | ||
94 | return si.impl.Stop() | 95 | return si.impl.Stop() |
95 | } | 96 | } |
diff --git a/src/gnunet/transport/channel.go b/src/gnunet/transport/channel.go index 8502d8f..4005759 100644 --- a/src/gnunet/transport/channel.go +++ b/src/gnunet/transport/channel.go | |||
@@ -11,6 +11,7 @@ import ( | |||
11 | "gnunet/message" | 11 | "gnunet/message" |
12 | ) | 12 | ) |
13 | 13 | ||
14 | // Error codes | ||
14 | var ( | 15 | var ( |
15 | ErrChannelNotImplemented = fmt.Errorf("Protocol not implemented") | 16 | ErrChannelNotImplemented = fmt.Errorf("Protocol not implemented") |
16 | ErrChannelNotOpened = fmt.Errorf("Channel not opened") | 17 | ErrChannelNotOpened = fmt.Errorf("Channel not opened") |
diff --git a/src/gnunet/transport/channel_netw.go b/src/gnunet/transport/channel_netw.go index 69ddda5..ecfd8e2 100644 --- a/src/gnunet/transport/channel_netw.go +++ b/src/gnunet/transport/channel_netw.go | |||
@@ -14,11 +14,12 @@ import ( | |||
14 | 14 | ||
15 | // NetworkChannel | 15 | // NetworkChannel |
16 | type NetworkChannel struct { | 16 | type NetworkChannel struct { |
17 | network string | 17 | network string // network protocol identifier ("tcp", "unix", ...) |
18 | conn net.Conn | 18 | conn net.Conn // associated connection |
19 | } | 19 | } |
20 | 20 | ||
21 | // NewNetworkChannel | 21 | // NewNetworkChannel creates a new channel for a given network protocol. |
22 | // The channel is in pending state and need to be opened before use. | ||
22 | func NewNetworkChannel(netw string) Channel { | 23 | func NewNetworkChannel(netw string) Channel { |
23 | return &NetworkChannel{ | 24 | return &NetworkChannel{ |
24 | network: netw, | 25 | network: netw, |
@@ -26,7 +27,11 @@ func NewNetworkChannel(netw string) Channel { | |||
26 | } | 27 | } |
27 | } | 28 | } |
28 | 29 | ||
29 | // Open | 30 | // Open a network channel based on specification: |
31 | // The specification is a string separated into parts by the '+' delimiter | ||
32 | // (e.g. "unix+/tmp/gnunet-service-gns-go.sock+perm=0770"). The network | ||
33 | // identifier (first part) must match the network specification of the | ||
34 | // underlaying NetworkChannel instance. | ||
30 | func (c *NetworkChannel) Open(spec string) (err error) { | 35 | func (c *NetworkChannel) Open(spec string) (err error) { |
31 | parts := strings.Split(spec, "+") | 36 | parts := strings.Split(spec, "+") |
32 | // check for correct protocol | 37 | // check for correct protocol |
@@ -38,7 +43,7 @@ func (c *NetworkChannel) Open(spec string) (err error) { | |||
38 | return | 43 | return |
39 | } | 44 | } |
40 | 45 | ||
41 | // Close | 46 | // Close a network channel |
42 | func (c *NetworkChannel) Close() error { | 47 | func (c *NetworkChannel) Close() error { |
43 | if c.conn != nil { | 48 | if c.conn != nil { |
44 | return c.conn.Close() | 49 | return c.conn.Close() |
@@ -46,7 +51,8 @@ func (c *NetworkChannel) Close() error { | |||
46 | return ErrChannelNotOpened | 51 | return ErrChannelNotOpened |
47 | } | 52 | } |
48 | 53 | ||
49 | // Read | 54 | // Read bytes from a network channel into buffer: Returns the number of read |
55 | // bytes and an error code. Only works on open channels ;) | ||
50 | func (c *NetworkChannel) Read(buf []byte) (int, error) { | 56 | func (c *NetworkChannel) Read(buf []byte) (int, error) { |
51 | if c.conn == nil { | 57 | if c.conn == nil { |
52 | return 0, ErrChannelNotOpened | 58 | return 0, ErrChannelNotOpened |
@@ -54,7 +60,8 @@ func (c *NetworkChannel) Read(buf []byte) (int, error) { | |||
54 | return c.conn.Read(buf) | 60 | return c.conn.Read(buf) |
55 | } | 61 | } |
56 | 62 | ||
57 | // Write | 63 | // Write buffer to a network channel: Returns the number of written bytes and |
64 | // an error code. | ||
58 | func (c *NetworkChannel) Write(buf []byte) (int, error) { | 65 | func (c *NetworkChannel) Write(buf []byte) (int, error) { |
59 | if c.conn == nil { | 66 | if c.conn == nil { |
60 | return 0, ErrChannelNotOpened | 67 | return 0, ErrChannelNotOpened |
@@ -67,8 +74,8 @@ func (c *NetworkChannel) Write(buf []byte) (int, error) { | |||
67 | 74 | ||
68 | // NetworkChannelServer | 75 | // NetworkChannelServer |
69 | type NetworkChannelServer struct { | 76 | type NetworkChannelServer struct { |
70 | network string | 77 | network string // network protocol to listen on |
71 | listener net.Listener | 78 | listener net.Listener // reference to listener object |
72 | } | 79 | } |
73 | 80 | ||
74 | // NewNetworkChannelServer | 81 | // NewNetworkChannelServer |
@@ -79,7 +86,9 @@ func NewNetworkChannelServer(netw string) ChannelServer { | |||
79 | } | 86 | } |
80 | } | 87 | } |
81 | 88 | ||
82 | // Open | 89 | // Open a network channel server (= start running it) based on the given |
90 | // specification. For every client connection to the server, the associated | ||
91 | // network channel for the connection is send via the hdlr channel. | ||
83 | func (s *NetworkChannelServer) Open(spec string, hdlr chan<- Channel) (err error) { | 92 | func (s *NetworkChannelServer) Open(spec string, hdlr chan<- Channel) (err error) { |
84 | parts := strings.Split(spec, "+") | 93 | parts := strings.Split(spec, "+") |
85 | // check for correct protocol | 94 | // check for correct protocol |
@@ -136,7 +145,7 @@ func (s *NetworkChannelServer) Open(spec string, hdlr chan<- Channel) (err error | |||
136 | return nil | 145 | return nil |
137 | } | 146 | } |
138 | 147 | ||
139 | // Close | 148 | // Close a network channel server (= stop the server) |
140 | func (s *NetworkChannelServer) Close() error { | 149 | func (s *NetworkChannelServer) Close() error { |
141 | if s.listener != nil { | 150 | if s.listener != nil { |
142 | err := s.listener.Close() | 151 | err := s.listener.Close() |
@@ -147,27 +156,35 @@ func (s *NetworkChannelServer) Close() error { | |||
147 | } | 156 | } |
148 | 157 | ||
149 | //////////////////////////////////////////////////////////////////////// | 158 | //////////////////////////////////////////////////////////////////////// |
159 | // helper functions to instantiate network channels and servers for | ||
160 | // common network protocols | ||
150 | 161 | ||
162 | // NewSocketChannel: Unix Domain Socket connection | ||
151 | func NewSocketChannel() Channel { | 163 | func NewSocketChannel() Channel { |
152 | return NewNetworkChannel("unix") | 164 | return NewNetworkChannel("unix") |
153 | } | 165 | } |
154 | 166 | ||
167 | // NewTCPChannel: TCP connection | ||
155 | func NewTCPChannel() Channel { | 168 | func NewTCPChannel() Channel { |
156 | return NewNetworkChannel("tcp") | 169 | return NewNetworkChannel("tcp") |
157 | } | 170 | } |
158 | 171 | ||
172 | // NewUDPChannel: UDP connection | ||
159 | func NewUDPChannel() Channel { | 173 | func NewUDPChannel() Channel { |
160 | return NewNetworkChannel("udp") | 174 | return NewNetworkChannel("udp") |
161 | } | 175 | } |
162 | 176 | ||
177 | // NewSocketChannelServer: Unix Domain Socket listener | ||
163 | func NewSocketChannelServer() ChannelServer { | 178 | func NewSocketChannelServer() ChannelServer { |
164 | return NewNetworkChannelServer("unix") | 179 | return NewNetworkChannelServer("unix") |
165 | } | 180 | } |
166 | 181 | ||
182 | // NewTCPChannelServer: TCP listener | ||
167 | func NewTCPChannelServer() ChannelServer { | 183 | func NewTCPChannelServer() ChannelServer { |
168 | return NewNetworkChannelServer("tcp") | 184 | return NewNetworkChannelServer("tcp") |
169 | } | 185 | } |
170 | 186 | ||
187 | // NewUDPChannelServer: UDP listener | ||
171 | func NewUDPChannelServer() ChannelServer { | 188 | func NewUDPChannelServer() ChannelServer { |
172 | return NewNetworkChannelServer("udp") | 189 | return NewNetworkChannelServer("udp") |
173 | } | 190 | } |
diff --git a/src/gnunet/transport/connection.go b/src/gnunet/transport/connection.go index e66bec1..1cf0317 100644 --- a/src/gnunet/transport/connection.go +++ b/src/gnunet/transport/connection.go | |||
@@ -5,7 +5,6 @@ import ( | |||
5 | "gnunet/message" | 5 | "gnunet/message" |
6 | ) | 6 | ) |
7 | 7 | ||
8 | //////////////////////////////////////////////////////////////////////// | ||
9 | // Connection for communicating peers | 8 | // Connection for communicating peers |
10 | type Connection struct { | 9 | type Connection struct { |
11 | from, to *core.Peer | 10 | from, to *core.Peer |
@@ -17,6 +16,8 @@ type Connection struct { | |||
17 | shared []byte | 16 | shared []byte |
18 | } | 17 | } |
19 | 18 | ||
19 | // NewConnection instanciates a new connection between peers communicating | ||
20 | // over a message channel (Connections are authenticated and secured). | ||
20 | func NewConnection(ch *MsgChannel, from, to *core.Peer) *Connection { | 21 | func NewConnection(ch *MsgChannel, from, to *core.Peer) *Connection { |
21 | return &Connection{ | 22 | return &Connection{ |
22 | from: from, | 23 | from: from, |
@@ -26,27 +27,33 @@ func NewConnection(ch *MsgChannel, from, to *core.Peer) *Connection { | |||
26 | } | 27 | } |
27 | } | 28 | } |
28 | 29 | ||
30 | // SharedSecret computes the shared secret the two endpoints of a connection. | ||
29 | func (c *Connection) SharedSecret(secret []byte) { | 31 | func (c *Connection) SharedSecret(secret []byte) { |
30 | c.shared = make([]byte, len(secret)) | 32 | c.shared = make([]byte, len(secret)) |
31 | copy(c.shared, secret) | 33 | copy(c.shared, secret) |
32 | } | 34 | } |
33 | 35 | ||
36 | // GetState returns the current state of the connection. | ||
34 | func (c *Connection) GetState() int { | 37 | func (c *Connection) GetState() int { |
35 | return c.state | 38 | return c.state |
36 | } | 39 | } |
37 | 40 | ||
41 | // SetBandwidth to control transfer rates on the connection | ||
38 | func (c *Connection) SetBandwidth(bw uint32) { | 42 | func (c *Connection) SetBandwidth(bw uint32) { |
39 | c.bandwidth = bw | 43 | c.bandwidth = bw |
40 | } | 44 | } |
41 | 45 | ||
46 | // Close connection between two peers. | ||
42 | func (c *Connection) Close() error { | 47 | func (c *Connection) Close() error { |
43 | return c.ch.Close() | 48 | return c.ch.Close() |
44 | } | 49 | } |
45 | 50 | ||
51 | // Send a message on the connection | ||
46 | func (c *Connection) Send(msg message.Message) error { | 52 | func (c *Connection) Send(msg message.Message) error { |
47 | return c.ch.Send(msg) | 53 | return c.ch.Send(msg) |
48 | } | 54 | } |
49 | 55 | ||
56 | // Receive a message on the connection | ||
50 | func (c *Connection) Receive() (message.Message, error) { | 57 | func (c *Connection) Receive() (message.Message, error) { |
51 | return c.ch.Receive() | 58 | return c.ch.Receive() |
52 | } | 59 | } |
diff --git a/src/gnunet/transport/session.go b/src/gnunet/transport/session.go index 90e4016..7d33ea2 100644 --- a/src/gnunet/transport/session.go +++ b/src/gnunet/transport/session.go | |||
@@ -1,7 +1,6 @@ | |||
1 | package transport | 1 | package transport |
2 | 2 | ||
3 | import () | 3 | // Session states |
4 | |||
5 | const ( | 4 | const ( |
6 | KX_STATE_DOWN = iota // No handshake yet. | 5 | KX_STATE_DOWN = iota // No handshake yet. |
7 | KX_STATE_KEY_SENT // We've sent our session key. | 6 | KX_STATE_KEY_SENT // We've sent our session key. |
diff --git a/src/gnunet/util/address.go b/src/gnunet/util/address.go index 04e2254..37fb102 100644 --- a/src/gnunet/util/address.go +++ b/src/gnunet/util/address.go | |||
@@ -1,29 +1,19 @@ | |||
1 | package util | 1 | package util |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/hex" | ||
4 | "fmt" | 5 | "fmt" |
6 | "net" | ||
5 | ) | 7 | ) |
6 | 8 | ||
7 | type IPAddress struct { | 9 | // Address specifies how a peer is reachable on the network. |
8 | Host []byte `size:"*-2"` | ||
9 | Port uint16 `order:"big"` | ||
10 | } | ||
11 | |||
12 | func NewIPAddress(host []byte, port uint16) *IPAddress { | ||
13 | ip := &IPAddress{ | ||
14 | Host: make([]byte, len(host)), | ||
15 | Port: port, | ||
16 | } | ||
17 | copy(ip.Host, host) | ||
18 | return ip | ||
19 | } | ||
20 | |||
21 | type Address struct { | 10 | type Address struct { |
22 | Transport string | 11 | Transport string // transport protocol |
23 | Options uint32 `order:"big"` | 12 | Options uint32 `order:"big"` // address options |
24 | Address []byte `size:"*"` | 13 | Address []byte `size:"*"` // address data (protocol-dependent) |
25 | } | 14 | } |
26 | 15 | ||
16 | // NewAddress returns a new Address for the given transport and specs | ||
27 | func NewAddress(transport string, addr []byte) *Address { | 17 | func NewAddress(transport string, addr []byte) *Address { |
28 | a := &Address{ | 18 | a := &Address{ |
29 | Transport: transport, | 19 | Transport: transport, |
@@ -34,6 +24,37 @@ func NewAddress(transport string, addr []byte) *Address { | |||
34 | return a | 24 | return a |
35 | } | 25 | } |
36 | 26 | ||
27 | // String returns a human-readable representation of an address. | ||
37 | func (a *Address) String() string { | 28 | func (a *Address) String() string { |
38 | return fmt.Sprintf("Address{%s}", AddressString(a.Transport, a.Address)) | 29 | return fmt.Sprintf("Address{%s}", AddressString(a.Transport, a.Address)) |
39 | } | 30 | } |
31 | |||
32 | //---------------------------------------------------------------------- | ||
33 | |||
34 | // AddressString returns a string representaion of an address. | ||
35 | func AddressString(transport string, addr []byte) string { | ||
36 | if transport == "tcp" || transport == "udp" { | ||
37 | alen := len(addr) | ||
38 | port := uint(addr[alen-2])*256 + uint(addr[alen-1]) | ||
39 | return fmt.Sprintf("%s:%s:%d", transport, net.IP(addr[:alen-2]).String(), port) | ||
40 | } | ||
41 | return fmt.Sprintf("%s:%s", transport, hex.EncodeToString(addr)) | ||
42 | } | ||
43 | |||
44 | //---------------------------------------------------------------------- | ||
45 | |||
46 | // IP address (can be IPv4 or IPv6 or a DNS name) | ||
47 | type IPAddress struct { | ||
48 | Host []byte `size:"*-2"` | ||
49 | Port uint16 `order:"big"` | ||
50 | } | ||
51 | |||
52 | // NewIPAddress creates a new instance for a given host and port. | ||
53 | func NewIPAddress(host []byte, port uint16) *IPAddress { | ||
54 | ip := &IPAddress{ | ||
55 | Host: make([]byte, len(host)), | ||
56 | Port: port, | ||
57 | } | ||
58 | copy(ip.Host, host) | ||
59 | return ip | ||
60 | } | ||
diff --git a/src/gnunet/util/array.go b/src/gnunet/util/array.go index 9076516..f6213bf 100644 --- a/src/gnunet/util/array.go +++ b/src/gnunet/util/array.go | |||
@@ -30,6 +30,16 @@ func Reverse(b []byte) []byte { | |||
30 | return r | 30 | return r |
31 | } | 31 | } |
32 | 32 | ||
33 | // IsNull returns true if all bytes in an array are set to 0. | ||
34 | func IsNull(b []byte) bool { | ||
35 | for _, v := range b { | ||
36 | if v != 0 { | ||
37 | return false | ||
38 | } | ||
39 | } | ||
40 | return true | ||
41 | } | ||
42 | |||
33 | // CopyBlock copies 'in' to 'out' so that 'out' is filled completely. | 43 | // CopyBlock copies 'in' to 'out' so that 'out' is filled completely. |
34 | // - If 'in' is larger than 'out', it is left-truncated before copy | 44 | // - If 'in' is larger than 'out', it is left-truncated before copy |
35 | // - If 'in' is smaller than 'out', it is left-padded with 0 before copy | 45 | // - If 'in' is smaller than 'out', it is left-padded with 0 before copy |
diff --git a/src/gnunet/util/format.go b/src/gnunet/util/format.go index 722b9a7..780c814 100644 --- a/src/gnunet/util/format.go +++ b/src/gnunet/util/format.go | |||
@@ -1,22 +1,13 @@ | |||
1 | package util | 1 | package util |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "encoding/hex" | ||
5 | "fmt" | 4 | "fmt" |
6 | "net" | ||
7 | ) | 5 | ) |
8 | 6 | ||
9 | func AddressString(transport string, addr []byte) string { | ||
10 | if transport == "tcp" || transport == "udp" { | ||
11 | alen := len(addr) | ||
12 | port := uint(addr[alen-2])*256 + uint(addr[alen-1]) | ||
13 | return fmt.Sprintf("%s:%s:%d", transport, net.IP(addr[:alen-2]).String(), port) | ||
14 | } | ||
15 | return fmt.Sprintf("%s:%s", transport, hex.EncodeToString(addr)) | ||
16 | } | ||
17 | |||
18 | var scale = " kMGTPEO" | 7 | var scale = " kMGTPEO" |
19 | 8 | ||
9 | // Scale1024 returns an integer value (e.g. a size) as a human-readable | ||
10 | // string with scales: a size of 183467245 would result in "174,967M" | ||
20 | func Scale1024(n uint64) string { | 11 | func Scale1024(n uint64) string { |
21 | v := float64(n) | 12 | v := float64(n) |
22 | var i int | 13 | var i int |
diff --git a/src/gnunet/util/id.go b/src/gnunet/util/id.go index 41bd30e..ab9b98c 100644 --- a/src/gnunet/util/id.go +++ b/src/gnunet/util/id.go | |||
@@ -4,7 +4,8 @@ var ( | |||
4 | _id = 0 | 4 | _id = 0 |
5 | ) | 5 | ) |
6 | 6 | ||
7 | // generate next unique identifier (unique in the running process/application) | ||
7 | func NextID() int { | 8 | func NextID() int { |
8 | _id += 1 | 9 | _id++ |
9 | return _id | 10 | return _id |
10 | } | 11 | } |
diff --git a/src/gnunet/util/peer_id.go b/src/gnunet/util/peer_id.go index 03bc73e..6549d75 100644 --- a/src/gnunet/util/peer_id.go +++ b/src/gnunet/util/peer_id.go | |||
@@ -1,9 +1,11 @@ | |||
1 | package util | 1 | package util |
2 | 2 | ||
3 | // PeerID is the 32-byte binary representation od a Ed25519 key | ||
3 | type PeerID struct { | 4 | type PeerID struct { |
4 | Key []byte `size:"32"` | 5 | Key []byte `size:"32"` |
5 | } | 6 | } |
6 | 7 | ||
8 | // NewPeerID creates a new object from the data. | ||
7 | func NewPeerID(data []byte) *PeerID { | 9 | func NewPeerID(data []byte) *PeerID { |
8 | if data == nil { | 10 | if data == nil { |
9 | data = make([]byte, 32) | 11 | data = make([]byte, 32) |
@@ -22,6 +24,7 @@ func NewPeerID(data []byte) *PeerID { | |||
22 | } | 24 | } |
23 | } | 25 | } |
24 | 26 | ||
27 | // String returns a human-readable representation of a peer id. | ||
25 | func (p *PeerID) String() string { | 28 | func (p *PeerID) String() string { |
26 | return EncodeBinaryToString(p.Key) | 29 | return EncodeBinaryToString(p.Key) |
27 | } | 30 | } |
diff --git a/src/gnunet/util/rnd.go b/src/gnunet/util/rnd.go index d3c8b2e..a9f247f 100644 --- a/src/gnunet/util/rnd.go +++ b/src/gnunet/util/rnd.go | |||
@@ -6,16 +6,19 @@ import ( | |||
6 | "encoding/binary" | 6 | "encoding/binary" |
7 | ) | 7 | ) |
8 | 8 | ||
9 | // RndArray fills a buffer with random content | ||
9 | func RndArray(b []byte) { | 10 | func RndArray(b []byte) { |
10 | rand.Read(b) | 11 | rand.Read(b) |
11 | } | 12 | } |
12 | 13 | ||
14 | // NewRndArray creates a new buffer of given size; filled with random content. | ||
13 | func NewRndArray(size int) []byte { | 15 | func NewRndArray(size int) []byte { |
14 | b := make([]byte, size) | 16 | b := make([]byte, size) |
15 | rand.Read(b) | 17 | rand.Read(b) |
16 | return b | 18 | return b |
17 | } | 19 | } |
18 | 20 | ||
21 | // RndUInt64 returns a new 64-bit unsigned random integer. | ||
19 | func RndUInt64() uint64 { | 22 | func RndUInt64() uint64 { |
20 | b := make([]byte, 8) | 23 | b := make([]byte, 8) |
21 | RndArray(b) | 24 | RndArray(b) |
@@ -25,22 +28,27 @@ func RndUInt64() uint64 { | |||
25 | return v | 28 | return v |
26 | } | 29 | } |
27 | 30 | ||
31 | // RndInt64 returns a new 64-bit signed random integer. | ||
28 | func RndInt64() int64 { | 32 | func RndInt64() int64 { |
29 | return int64(RndUInt64()) | 33 | return int64(RndUInt64()) |
30 | } | 34 | } |
31 | 35 | ||
36 | // RndUInt32 returns a new 32-bit unsigned random integer. | ||
32 | func RndUInt32() uint32 { | 37 | func RndUInt32() uint32 { |
33 | return uint32(RndUInt64()) | 38 | return uint32(RndUInt64()) |
34 | } | 39 | } |
35 | 40 | ||
41 | // RndInt32 returns a new 32-bit signed random integer. | ||
36 | func RndInt32() int32 { | 42 | func RndInt32() int32 { |
37 | return int32(RndUInt64()) | 43 | return int32(RndUInt64()) |
38 | } | 44 | } |
39 | 45 | ||
46 | // RndUInt16 returns a new 16-bit unsigned random integer. | ||
40 | func RndUInt16() uint16 { | 47 | func RndUInt16() uint16 { |
41 | return uint16(RndUInt64()) | 48 | return uint16(RndUInt64()) |
42 | } | 49 | } |
43 | 50 | ||
51 | // RndInt16 returns a new 16-bit signed random integer. | ||
44 | func RndInt16() int16 { | 52 | func RndInt16() int16 { |
45 | return int16(RndUInt64()) | 53 | return int16(RndUInt64()) |
46 | } | 54 | } |