[
  {
    "path": ".gitignore",
    "content": "test\ndrcom.conf\ntest.conf\ndogcom\nmain\n.vscode\n\n# Prerequisites\n*.d\n\n# Object files\n*.o\n*.ko\n*.obj\n*.elf\n\n# Linker output\n*.ilk\n*.map\n*.exp\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Libraries\n*.lib\n*.a\n*.la\n*.lo\n\n# Shared objects (inc. Windows DLLs)\n*.dll\n*.so\n*.so.*\n*.dylib\n\n# Executables\n*.exe\n*.out\n*.app\n*.i*86\n*.x86_64\n*.hex\n\n# Debug files\n*.dSYM/\n*.su\n*.idb\n*.pdb\n\n# Kernel Module Compile Results\n*.mod*\n*.cmd\nmodules.order\nModule.symvers\nMkfile.old\ndkms.conf\n*.stackdump"
  },
  {
    "path": ".travis.yml",
    "content": "language: c\nos:\n    - linux\n    - osx\ncompiler:\n    - gcc\n    - clang\n\nscript:\n    - make test=y\n    - ./dogcom -m dhcp -c sample-d.conf\n    - ./dogcom -m pppoe -c sample-p.conf\n\nbranches:\n    only:\n        - master"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published\n    by the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<http://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "Makefile",
    "content": "CC     = gcc\nTARGET = dogcom\nINSTALL_DIR = /usr/bin/\n\nifeq ($(debug), y)\n\tCFLAGS += -DDEBUG -g\nendif\n\nifeq ($(win32), y)\n\tCFLAGS += -lws2_32\n\t# TARGET = dogcom.exe\nendif\n\nifeq ($(static), y)\n\tCFLAGS += -static\nendif\n\nifeq ($(strip), y)\n\tCFLAGS += -Os -s -Wno-unused-result\nendif\n\nifeq ($(force_encrypt), y)\n\tCFLAGS += -DFORCE_ENCRYPT\nendif\n\nifeq ($(test), y)\n\tCFLAGS += -std=gnu99 -Werror -DTEST\nelse\n\tCFLAGS += -std=gnu99 -Werror\nendif\n\nSOURCES = $(wildcard *.c) $(wildcard libs/*.c)\nOBJS    = $(patsubst %.c, %.o, $(SOURCES))\n\n$(TARGET):\t$(OBJS)\n\t$(CC) $(DEBUG) $(TEST) $(OBJS) $(CFLAGS) -o $(TARGET)\n\nall:\t$(TARGET)\n\ninstall:\t$(TARGET)\n\tcp $(TARGET) $(INSTALL_DIR)\n\nclean:\n\trm -f $(OBJS)\n\trm -f $(TARGET)\n\ndistclean:  clean\n\n.PHONY: all clean distclean install\n"
  },
  {
    "path": "README.md",
    "content": "# dogcom [![travis-ci](https://travis-ci.org/mchome/dogcom.svg \"Build status\")](https://travis-ci.org/mchome/dogcom) [![badge](https://img.shields.io/badge/%20built%20with-%20%E2%9D%A4-ff69b4.svg \"build with love\")](https://github.com/mchome/dogcom) [![version](https://img.shields.io/badge/stable%20-%20v1.6.2-4dc71f.svg \"stable version\")](https://github.com/mchome/dogcom/tree/v1.6.2)\n\n[Drcom-generic](https://github.com/drcoms/drcom-generic) implementation in C.\n\n```\nUsage:\n        dogcom -m <dhcp/pppoe> -c <FILEPATH> [options <argument>]...\n\nOptions:\n        --mode <dhcp/pppoe>, -m <dhcp/pppoe>  set your dogcom mode\n        --conf <FILEPATH>, -c <FILEPATH>      import configuration file\n        --bindip <IPADDR>, -b <IPADDR>        bind your ip address(default is 0.0.0.0)\n        --log <LOGPATH>, -l <LOGPATH>         specify log file\n        --802.1x, -x                          enable 802.1x\n        --daemon, -d                          set daemon flag\n        --eternal, -e                         set eternal flag\n        --verbose, -v                         set verbose flag\n        --help, -h                            display this help\n```\n\nConfig file is compatible with [drcom-generic](https://github.com/drcoms/drcom-generic).\n\n#### Example:\n\n```bash\n$ dogcom -m dhcp -c dogcom.conf\n$ dogcom -m dhcp -c dogcom.conf -l /tmp/dogcom.log -v\n$ dogcom -m dhcp -c dogcom.conf -d # (PS: only on Linux build)\n$ dogcom -m pppoe -c dogcom.conf -x # (PS: only on Linux build)\n$ dogcom -m pppoe -c dogcom.conf -e # eternal dogcoming (default times is 5)\n$ dogcom -m pppoe -c dogcom.conf -v\n$ dogcom -m dhcp -c dogcom.conf -b 10.2.3.12 -v\n```\n\n#### To build:\n\n```bash\n$ make # Linux\n$ make win32=y # Windows(MinGW)\n$ make test=y # For testing purposes\n$ make force_encrypt=y # Force open encrypt mode in PPPoE version\n```\n\n#### Openwrt-package\n[https://github.com/mchome/openwrt-dogcom](https://github.com/mchome/openwrt-dogcom)\n\n#### Tutorial\n[![asciicast](https://asciinema.org/a/9j7cj1s61jiczx2s0206tosjr.png)](https://asciinema.org/a/9j7cj1s61jiczx2s0206tosjr)\n\n### Thanks:\n- [gdut-drcom](https://github.com/chenhaowen01/gdut-drcom 'chenhaowen01')\n- [jlu-drcom-client](https://github.com/drcoms/jlu-drcom-client/tree/master/C-version 'feix')\n- [leetking](https://github.com/leetking 'leetking')\n\n### Special thanks:\n- [Drcom-generic](https://github.com/drcoms/drcom-generic 'ly0')\n\n### License:\n![AGPL V3](https://cloud.githubusercontent.com/assets/7392658/20011165/a0caabdc-a2e5-11e6-974c-8d4961c7d6d3.png)\n"
  },
  {
    "path": "auth.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/time.h>\n#include <time.h>\n#include <unistd.h>\n\n#ifdef WIN32\n#include <winsock2.h>\ntypedef int socklen_t;\n#else\n#include <arpa/inet.h>\n#include <netinet/in.h>\n#include <sys/socket.h>\n#endif\n\n#include \"auth.h\"\n#include \"configparse.h\"\n#include \"debug.h\"\n#include \"keepalive.h\"\n#include \"libs/md4.h\"\n#include \"libs/md5.h\"\n#include \"libs/sha1.h\"\n\n#define BIND_PORT 61440\n#define DEST_PORT 61440\n\nint dhcp_challenge(int sockfd, struct sockaddr_in addr, unsigned char seed[]) {\n    unsigned char challenge_packet[20], recv_packet[1024];\n    memset(challenge_packet, 0, 20);\n    challenge_packet[0] = 0x01;\n    challenge_packet[1] = 0x02;\n    challenge_packet[2] = rand() & 0xff;\n    challenge_packet[3] = rand() & 0xff;\n    challenge_packet[4] = drcom_config.AUTH_VERSION[0];\n\n    sendto(sockfd, challenge_packet, 20, 0, (struct sockaddr *)&addr, sizeof(addr));\n\n    if (verbose_flag) {\n        print_packet(\"[Challenge sent] \", challenge_packet, 20);\n    }\n    if (logging_flag) {\n        logging(\"[Challenge sent] \", challenge_packet, 20);\n    }\n#ifdef TEST\n    unsigned char test[4] = {0x52, 0x6c, 0xe4, 0x00};\n    memcpy(seed, test, 4);\n    print_packet(\"[TEST MODE]<PREP SEED> \", seed, 4);\n    return 0;\n#endif\n\n    socklen_t addrlen = sizeof(addr);\n    if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to recv data\");\n#else\n        perror(\"Failed to recv data\");\n#endif\n        return 1;\n    }\n\n    if (verbose_flag) {\n        print_packet(\"[Challenge recv] \", recv_packet, 76);\n    }\n    if (logging_flag) {\n        logging(\"[Challenge recv] \", recv_packet, 76);\n    }\n\n    if (recv_packet[0] != 0x02) {\n        printf(\"Bad challenge response received.\\n\");\n        return 1;\n    }\n\n    memcpy(seed, &recv_packet[4], 4);\n#ifdef DEBUG\n    print_packet(\"<GET SEED> \", seed, 4);\n#endif\n\n    return 0;\n}\n\nint dhcp_login(int sockfd, struct sockaddr_in addr, unsigned char seed[], unsigned char auth_information[], int try_JLUversion) {\n    unsigned int login_packet_size;\n    unsigned int length_padding = 0;\n    int JLU_padding = 0;\n\n    if (strlen(drcom_config.password) > 8) {\n        length_padding = strlen(drcom_config.password) - 8 + (length_padding % 2);\n        if (try_JLUversion) {\n            printf(\"Start JLU mode.\\n\");\n            if (logging_flag) {\n                logging(\"Start JLU mode.\", NULL, 0);\n            }\n            if (strlen(drcom_config.password) != 16) {\n                JLU_padding = strlen(drcom_config.password) / 4;\n            }\n            length_padding = 28 + (strlen(drcom_config.password) - 8) + JLU_padding;\n        }\n    }\n    if (drcom_config.ror_version) {\n        login_packet_size = 338 + length_padding;\n    } else {\n        login_packet_size = 330;\n    }\n    unsigned char login_packet[login_packet_size], recv_packet[1024], MD5A[16], MACxorMD5A[6], MD5B[16], checksum1[8], checksum2[4];\n    memset(login_packet, 0, login_packet_size);\n    memset(recv_packet, 0, 100);\n\n    // build login-packet\n    login_packet[0] = 0x03;\n    login_packet[1] = 0x01;\n    login_packet[2] = 0x00;\n    login_packet[3] = strlen(drcom_config.username) + 20;\n    int MD5A_len = 6 + strlen(drcom_config.password);\n    unsigned char MD5A_str[MD5A_len];\n    MD5A_str[0] = 0x03;\n    MD5A_str[1] = 0x01;\n    memcpy(MD5A_str + 2, seed, 4);\n    memcpy(MD5A_str + 6, drcom_config.password, strlen(drcom_config.password));\n    MD5(MD5A_str, MD5A_len, MD5A);\n    memcpy(login_packet + 4, MD5A, 16);\n    memcpy(login_packet + 20, drcom_config.username, strlen(drcom_config.username));\n    memcpy(login_packet + 56, &drcom_config.CONTROLCHECKSTATUS, 1);\n    memcpy(login_packet + 57, &drcom_config.ADAPTERNUM, 1);\n    uint64_t sum = 0;\n    uint64_t mac = 0;\n    // unpack\n    for (int i = 0; i < 6; i++) {\n        sum = (int)MD5A[i] + sum * 256;\n    }\n    // unpack\n    for (int i = 0; i < 6; i++) {\n        mac = (int)drcom_config.mac[i] + mac * 256;\n    }\n    sum ^= mac;\n    // pack\n    for (int i = 6; i > 0; i--) {\n        MACxorMD5A[i - 1] = (unsigned char)(sum % 256);\n        sum /= 256;\n    }\n    memcpy(login_packet + 58, MACxorMD5A, sizeof(MACxorMD5A));\n    int MD5B_len = 9 + strlen(drcom_config.password);\n    unsigned char MD5B_str[MD5B_len];\n    memset(MD5B_str, 0, MD5B_len);\n    MD5B_str[0] = 0x01;\n    memcpy(MD5B_str + 1, drcom_config.password, strlen(drcom_config.password));\n    memcpy(MD5B_str + strlen(drcom_config.password) + 1, seed, 4);\n    MD5(MD5B_str, MD5B_len, MD5B);\n    memcpy(login_packet + 64, MD5B, 16);\n    login_packet[80] = 0x01;\n    unsigned char host_ip[4];\n    sscanf(drcom_config.host_ip, \"%hhd.%hhd.%hhd.%hhd\",\n           &host_ip[0],\n           &host_ip[1],\n           &host_ip[2],\n           &host_ip[3]);\n    memcpy(login_packet + 81, host_ip, 4);\n    unsigned char checksum1_str[101], checksum1_tmp[4] = {0x14, 0x00, 0x07, 0x0b};\n    memcpy(checksum1_str, login_packet, 97);\n    memcpy(checksum1_str + 97, checksum1_tmp, 4);\n    MD5(checksum1_str, 101, checksum1);\n    memcpy(login_packet + 97, checksum1, 8);\n    memcpy(login_packet + 105, &drcom_config.IPDOG, 1);\n    memcpy(login_packet + 110, &drcom_config.host_name, strlen(drcom_config.host_name));\n    unsigned char PRIMARY_DNS[4];\n    sscanf(drcom_config.PRIMARY_DNS, \"%hhd.%hhd.%hhd.%hhd\",\n           &PRIMARY_DNS[0],\n           &PRIMARY_DNS[1],\n           &PRIMARY_DNS[2],\n           &PRIMARY_DNS[3]);\n    memcpy(login_packet + 142, PRIMARY_DNS, 4);\n    unsigned char dhcp_server[4];\n    sscanf(drcom_config.dhcp_server, \"%hhd.%hhd.%hhd.%hhd\",\n           &dhcp_server[0],\n           &dhcp_server[1],\n           &dhcp_server[2],\n           &dhcp_server[3]);\n    memcpy(login_packet + 146, dhcp_server, 4);\n    unsigned char OSVersionInfoSize[4] = {0x94};\n    unsigned char OSMajor[4] = {0x05};\n    unsigned char OSMinor[4] = {0x01};\n    unsigned char OSBuild[4] = {0x28, 0x0a};\n    unsigned char PlatformID[4] = {0x02};\n    if (try_JLUversion) {\n        OSVersionInfoSize[0] = 0x94;\n        OSMajor[0] = 0x06;\n        OSMinor[0] = 0x02;\n        OSBuild[0] = 0xf0;\n        OSBuild[1] = 0x23;\n        PlatformID[0] = 0x02;\n        unsigned char ServicePack[40] = {0x33, 0x64, 0x63, 0x37, 0x39, 0x66, 0x35, 0x32, 0x31, 0x32, 0x65, 0x38, 0x31, 0x37, 0x30, 0x61, 0x63, 0x66, 0x61, 0x39, 0x65, 0x63, 0x39, 0x35, 0x66, 0x31, 0x64, 0x37, 0x34, 0x39, 0x31, 0x36, 0x35, 0x34, 0x32, 0x62, 0x65, 0x37, 0x62, 0x31};\n        unsigned char hostname[9] = {0x44, 0x72, 0x43, 0x4f, 0x4d, 0x00, 0xcf, 0x07, 0x68};\n        memcpy(login_packet + 182, hostname, 9);\n        memcpy(login_packet + 246, ServicePack, 40);\n    }\n    memcpy(login_packet + 162, OSVersionInfoSize, 4);\n    memcpy(login_packet + 166, OSMajor, 4);\n    memcpy(login_packet + 170, OSMinor, 4);\n    memcpy(login_packet + 174, OSBuild, 4);\n    memcpy(login_packet + 178, PlatformID, 4);\n    if (!try_JLUversion) {\n        memcpy(login_packet + 182, &drcom_config.host_os, strlen(drcom_config.host_os));\n    }\n    memcpy(login_packet + 310, drcom_config.AUTH_VERSION, 2);\n    int counter = 312;\n    unsigned int ror_padding = 0;\n    if (strlen(drcom_config.password) <= 8) {\n        ror_padding = 8 - strlen(drcom_config.password);\n    } else {\n        if ((strlen(drcom_config.password) - 8) % 2) {\n            ror_padding = 1;\n        }\n        if (try_JLUversion) {\n            ror_padding = JLU_padding;\n        }\n    }\n    if (drcom_config.ror_version) {\n        MD5(MD5A_str, MD5A_len, MD5A);\n        login_packet[counter + 1] = strlen(drcom_config.password);\n        counter += 2;\n        for (int i = 0, x = 0; i < strlen(drcom_config.password); i++) {\n            x = (int)MD5A[i] ^ (int)drcom_config.password[i];\n            login_packet[counter + i] = (unsigned char)(((x << 3) & 0xff) + (x >> 5));\n        }\n        counter += strlen(drcom_config.password);\n        // print_packet(\"TEST \", ror, strlen(drcom_config.password));\n    } else {\n        ror_padding = 2;\n    }\n    login_packet[counter] = 0x02;\n    login_packet[counter + 1] = 0x0c;\n    unsigned char checksum2_str[counter + 18];  // [counter + 14 + 4]\n    memset(checksum2_str, 0, counter + 18);\n    unsigned char checksum2_tmp[6] = {0x01, 0x26, 0x07, 0x11};\n    memcpy(checksum2_str, login_packet, counter + 2);\n    memcpy(checksum2_str + counter + 2, checksum2_tmp, 6);\n    memcpy(checksum2_str + counter + 8, drcom_config.mac, 6);\n    sum = 1234;\n    uint64_t ret = 0;\n    for (int i = 0; i < counter + 14; i += 4) {\n        ret = 0;\n        // reverse unsigned char array[4]\n        for (int j = 4; j > 0; j--) {\n            ret = ret * 256 + (int)checksum2_str[i + j - 1];\n        }\n        sum ^= ret;\n    }\n    sum = (1968 * sum) & 0xffffffff;\n    for (int j = 0; j < 4; j++) {\n        checksum2[j] = (unsigned char)(sum >> (j * 8) & 0xff);\n    }\n    memcpy(login_packet + counter + 2, checksum2, 4);\n    memcpy(login_packet + counter + 8, drcom_config.mac, 6);\n    login_packet[counter + ror_padding + 14] = 0xe9;\n    login_packet[counter + ror_padding + 15] = 0x13;\n    if (try_JLUversion) {\n        login_packet[counter + ror_padding + 14] = 0x60;\n        login_packet[counter + ror_padding + 15] = 0xa2;\n    }\n\n    sendto(sockfd, login_packet, sizeof(login_packet), 0, (struct sockaddr *)&addr, sizeof(addr));\n\n    if (verbose_flag) {\n        print_packet(\"[Login sent] \", login_packet, sizeof(login_packet));\n    }\n    if (logging_flag) {\n        logging(\"[Login sent] \", login_packet, sizeof(login_packet));\n    }\n\n#ifdef TEST\n    unsigned char test[16] = {0x44, 0x72, 0x63, 0x6f, 0x77, 0x27, 0x20, 0xca, 0xed, 0x05, 0x6e, 0x35, 0xaa, 0x8b, 0x01, 0xfb};\n    memcpy(auth_information, test, 16);\n    print_packet(\"[TEST MODE]<PREP AUTH_INFORMATION> \", auth_information, 16);\n    return 0;\n#endif\n\n    socklen_t addrlen = sizeof(addr);\n    if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to recv data\");\n#else\n        perror(\"Failed to recv data\");\n#endif\n        return 1;\n    }\n\n    if (recv_packet[0] != 0x04) {\n        if (verbose_flag) {\n            print_packet(\"[login recv] \", recv_packet, 100);\n        }\n        printf(\"<<< Login failed >>>\\n\");\n        if (logging_flag) {\n            logging(\"[login recv] \", recv_packet, 100);\n            logging(\"<<< Login failed >>>\", NULL, 0);\n        }\n        char err_msg[256];\n        if (recv_packet[0] == 0x05) {\n            switch (recv_packet[4]) {\n                case CHECK_MAC:\n                    strcpy(err_msg, \"[Tips] Someone is using this account with wired.\");\n                    break;\n                case SERVER_BUSY:\n                    strcpy(err_msg, \"[Tips] The server is busy, please log back in again.\");\n                    break;\n                case WRONG_PASS:\n                    strcpy(err_msg, \"[Tips] Account and password not match.\");\n                    break;\n                case NOT_ENOUGH:\n                    strcpy(err_msg, \"[Tips] The cumulative time or traffic for this account has exceeded the limit.\");\n                    break;\n                case FREEZE_UP:\n                    strcpy(err_msg, \"[Tips] This account is suspended.\");\n                    break;\n                case NOT_ON_THIS_IP:\n                    strcpy(err_msg, \"[Tips] IP address does not match, this account can only be used in the specified IP address.\");\n                    break;\n                case NOT_ON_THIS_MAC:\n                    strcpy(err_msg, \"[Tips] MAC address does not match, this account can only be used in the specified IP and MAC address.\");\n                    break;\n                case TOO_MUCH_IP:\n                    strcpy(err_msg, \"[Tips] This account has too many IP addresses.\");\n                    break;\n                case UPDATE_CLIENT:\n                    strcpy(err_msg, \"[Tips] The client version is incorrect.\");\n                    break;\n                case NOT_ON_THIS_IP_MAC:\n                    strcpy(err_msg, \"[Tips] This account can only be used on specified MAC and IP address.\");\n                    break;\n                case MUST_USE_DHCP:\n                    strcpy(err_msg, \"[Tips] Your PC set up a static IP, please change to DHCP, and then re-login.\");\n                    break;\n                default:\n                    strcpy(err_msg, \"[Tips] Unknown error number.\");\n                    break;\n            }\n            printf(\"%s\\n\", err_msg);\n            if (logging_flag) {\n                logging(err_msg, NULL, 0);\n            }\n        }\n        return 1;\n    } else {\n        if (verbose_flag) {\n            print_packet(\"[login recv] \", recv_packet, 100);\n        }\n        printf(\"<<< Logged in >>>\\n\");\n        if (logging_flag) {\n            logging(\"[login recv] \", recv_packet, 100);\n            logging(\"<<< Logged in >>>\", NULL, 0);\n        }\n    }\n\n    memcpy(auth_information, &recv_packet[23], 16);\n#ifdef DEBUG\n    print_packet(\"<GET AUTH_INFORMATION> \", auth_information, 16);\n#endif\n\n    if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) >= 0) {\n        DEBUG_PRINT((\"Get notice packet.\"));\n    }\n\n    return 0;\n}\n\nint pppoe_challenge(int sockfd, struct sockaddr_in addr, int *pppoe_counter, unsigned char seed[], unsigned char sip[], int *encrypt_mode) {\n    unsigned char challenge_packet[8], recv_packet[1024];\n    memset(challenge_packet, 0, 8);\n    unsigned char challenge_tmp[5] = {0x07, 0x00, 0x08, 0x00, 0x01};\n    memcpy(challenge_packet, challenge_tmp, 5);\n    challenge_packet[1] = *pppoe_counter % 0xFF;\n    (*pppoe_counter)++;\n\n    sendto(sockfd, challenge_packet, 8, 0, (struct sockaddr *)&addr, sizeof(addr));\n\n    if (verbose_flag) {\n        print_packet(\"[Challenge sent] \", challenge_packet, 8);\n    }\n    if (logging_flag) {\n        logging(\"[Challenge sent] \", challenge_packet, 8);\n    }\n#ifdef TEST\n    unsigned char test1[4] = {0x26, 0xe6, 0xe1, 0x02};\n    unsigned char test2[4] = {0xc0, 0xa8, 0x01, 0x0b};\n    memcpy(seed, test1, 4);\n    memcpy(sip, test2, 4);\n    *encrypt_mode = 1; /* encrypt_mode test switch [0 or 1] */\n    print_packet(\"[TEST MODE]<PREP SEED> \", seed, 4);\n    print_packet(\"[TEST MODE]<PREP SIP> \", sip, 4);\n    printf(\"[TEST MODE]<PREP ENCRYPT_MODE> %d\\n\", *encrypt_mode);\n    return 0;\n#endif\n\n    socklen_t addrlen = sizeof(addr);\n    if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to recv data\");\n#else\n        perror(\"Failed to recv data\");\n#endif\n        return 1;\n    }\n\n    if (verbose_flag) {\n        print_packet(\"[Challenge recv] \", recv_packet, 32);\n    }\n    if (logging_flag) {\n        logging(\"[Challenge recv] \", recv_packet, 32);\n    }\n\n    if (recv_packet[0] != 0x07) {\n        printf(\"Bad challenge response received.\\n\");\n        return 1;\n    }\n    if (recv_packet[5] != 0x00) {\n        *encrypt_mode = 1;\n    } else {\n        *encrypt_mode = 0;\n    }\n\n#ifdef FORCE_ENCRYPT\n    *encrypt_mode = 1;\n#endif\n\n    memcpy(seed, &recv_packet[8], 4);\n    memcpy(sip, &recv_packet[12], 4);\n    memcpy(drcom_config.KEEP_ALIVE_VERSION, &recv_packet[28], 2);\n#ifdef DEBUG\n    print_packet(\"<GET SEED> \", seed, 4);\n    print_packet(\"<GET SIP> \", sip, 4);\n    printf(\"<GET ENCRYPT_MODE> %d\", *encrypt_mode);\n#endif\n\n    return 0;\n}\n\nint pppoe_login(int sockfd, struct sockaddr_in addr, int *pppoe_counter, unsigned char seed[], unsigned char sip[], int *login_first, int *encrypt_mode, int *encrypt_type) {\n    unsigned char login_packet[96], recv_packet[1024];\n    memset(login_packet, 0, 96);\n    unsigned char login_tmp[5] = {0x07, 0x00, 0x60, 0x00, 0x03};\n    memcpy(login_packet, login_tmp, 5);\n    login_packet[1] = *pppoe_counter % 0xFF;\n    (*pppoe_counter)++;\n    memcpy(login_packet + 12, sip, 4);\n    if (*login_first) {\n        login_packet[17] = 0x62;\n    } else {\n        login_packet[17] = 0x63;\n    }\n    memcpy(login_packet + 19, &drcom_config.pppoe_flag, 1);\n    memcpy(login_packet + 20, seed, 4);\n    unsigned char crc[8] = {0};\n    *encrypt_type = seed[0] & 3;\n    if (!*encrypt_mode) {\n        *encrypt_type = 0;\n    }\n    gen_crc(seed, *encrypt_type, crc);\n    unsigned char crc_tmp[32] = {0};\n    memcpy(crc_tmp, login_packet, 32);\n    memcpy(crc_tmp + 24, crc, 8);\n    uint64_t ret = 0;\n    uint64_t sum = 0;\n    unsigned char crc2[4] = {0};\n    if (*encrypt_type == 0) {\n        for (int i = 0; i < 32; i += 4) {\n            ret = 0;\n            for (int j = 4; j > 0; j--) {\n                ret = ret * 256 + (int)crc_tmp[i + j - 1];\n            }\n            sum ^= ret;\n            sum &= 0xffffffff;\n        }\n        sum = sum * 19680126 & 0xffffffff;\n        for (int i = 0; i < 4; i++) {\n            crc2[i] = (unsigned char)(sum % 256);\n            sum /= 256;\n        }\n        memcpy(login_packet + 24, crc2, 4);\n    } else {\n        memcpy(login_packet + 24, crc, 8);\n    }\n    // login_packet[39] = 0x8b;\n    // memcpy(login_packet + 40, sip, 4);\n    // unsigned char smask[4] = {0xff, 0xff, 0xff, 0xff};\n    // memcpy(login_packet + 44, smask, 4);\n    // login_packet[54] = 0x40;\n\n    sendto(sockfd, login_packet, 96, 0, (struct sockaddr *)&addr, sizeof(addr));\n    if (verbose_flag) {\n        print_packet(\"[PPPoE_login sent] \", login_packet, 96);\n    }\n    if (logging_flag) {\n        logging(\"[PPPoE_login sent] \", login_packet, 96);\n    }\n#ifdef TEST\n    return 0;\n#endif\n\n    socklen_t addrlen = sizeof(addr);\n    if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to recv data\");\n#else\n        perror(\"Failed to recv data\");\n#endif\n        return 1;\n    }\n\n    if (verbose_flag) {\n        print_packet(\"[PPPoE_login recv] \", recv_packet, 48);\n    }\n    if (logging_flag) {\n        logging(\"[PPPoE_login recv] \", recv_packet, 48);\n    }\n\n    if (recv_packet[0] != 0x07) {\n        printf(\"Bad pppoe_login response received.\\n\");\n        return 1;\n    }\n\n    if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) >= 0) {\n        DEBUG_PRINT((\"Get notice packet.\"));\n    }\n\n    return 0;\n}\n\nint dogcom(int try_times) {\n#ifdef WIN32\n    WORD sockVersion = MAKEWORD(2, 2);\n    WSADATA wsaData;\n    if (WSAStartup(sockVersion, &wsaData) != 0) {\n        return 1;\n    }\n#endif\n    int sockfd;\n\n    struct sockaddr_in bind_addr;\n    memset(&bind_addr, 0, sizeof(bind_addr));\n    bind_addr.sin_family = AF_INET;\n    if (verbose_flag) {\n        printf(\"You are binding at %s!\\n\\n\", bind_ip);\n    }\n#ifdef WIN32\n    bind_addr.sin_addr.S_un.S_addr = inet_addr(bind_ip);\n#else\n    bind_addr.sin_addr.s_addr = inet_addr(bind_ip);\n#endif\n    bind_addr.sin_port = htons(BIND_PORT);\n\n    struct sockaddr_in dest_addr;\n    memset(&dest_addr, 0, sizeof(dest_addr));\n    dest_addr.sin_family = AF_INET;\n#ifdef WIN32\n    dest_addr.sin_addr.S_un.S_addr = inet_addr(drcom_config.server);\n#else\n    dest_addr.sin_addr.s_addr = inet_addr(drcom_config.server);\n#endif\n    dest_addr.sin_port = htons(DEST_PORT);\n\n    srand(time(NULL));\n\n    // create socket\n    if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to create socket\");\n#else\n        perror(\"Failed to create socket\");\n#endif\n        return 1;\n    }\n    // bind socket\n    if (bind(sockfd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to bind socket\");\n#else\n        perror(\"Failed to bind socket\");\n#endif\n        return 1;\n    }\n\n    // set timeout\n#ifdef WIN32\n    int timeout = 3000;\n#else\n    struct timeval timeout;\n    timeout.tv_sec = 3;\n    timeout.tv_usec = 0;\n#endif\n    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to set sock opt\");\n#else\n        perror(\"Failed to set sock opt\");\n#endif\n        return 1;\n    }\n\n    // start dogcoming\n    if (strcmp(mode, \"dhcp\") == 0) {\n        int login_failed_attempts = 0;\n        int try_JLUversion = 0;\n        for (int try_counter = 0; try_counter < try_times; try_counter++) {\n            if (eternal_flag) {\n                try_counter = 0;\n            }\n            unsigned char seed[4];\n            unsigned char auth_information[16];\n            if (dhcp_challenge(sockfd, dest_addr, seed)) {\n                printf(\"Retrying...\\n\");\n                if (logging_flag) {\n                    logging(\"Retrying...\", NULL, 0);\n                }\n                sleep(3);\n            } else {\n                usleep(200000);  // 0.2 sec\n                if (login_failed_attempts > 2) {\n                    try_JLUversion = 1;\n                }\n                if (!dhcp_login(sockfd, dest_addr, seed, auth_information, try_JLUversion)) {\n                    int keepalive_counter = 0;\n                    int keepalive_try_counter = 0;\n                    int first = 1;\n                    while (1) {\n                        if (!keepalive_1(sockfd, dest_addr, seed, auth_information)) {\n                            usleep(200000);  // 0.2 sec\n                            if (keepalive_2(sockfd, dest_addr, &keepalive_counter, &first, 0)) {\n                                continue;\n                            }\n                            if (verbose_flag) {\n                                printf(\"Keepalive in loop.\\n\");\n                            }\n                            if (logging_flag) {\n                                logging(\"Keepalive in loop.\", NULL, 0);\n                            }\n                            sleep(20);\n                        } else {\n                            if (keepalive_try_counter > 5) {\n                                break;\n                            }\n                            keepalive_try_counter++;\n                            continue;\n                        }\n                    }\n                } else {\n                    login_failed_attempts += 1;\n                    printf(\"Retrying...\\n\");\n                    if (logging_flag) {\n                        logging(\"Retrying...\", NULL, 0);\n                    }\n                    sleep(3);\n                };\n            }\n        }\n    } else if (strcmp(mode, \"pppoe\") == 0) {\n        int pppoe_counter = 0;\n        int keepalive_counter = 0;\n        unsigned char seed[4], sip[4]; /* pppoe's seed == dhcp's KEEP_ALIVE_VERSION */\n        int login_first = 1;\n        int first = 1;\n        int encrypt_mode = 0;\n        int encrypt_type = 0;\n        int try_counter = 0;\n        while (1) {\n            if (pppoe_challenge(sockfd, dest_addr, &pppoe_counter, seed, sip, &encrypt_mode)) {\n                printf(\"Retrying...\\n\");\n                if (logging_flag) {\n                    logging(\"Retrying...\", NULL, 0);\n                }\n                login_first = 1;\n                try_counter++;\n                if (eternal_flag) {\n                    try_counter = 0;\n                }\n                if (try_counter >= try_times) {\n                    break;\n                }\n                sleep(5);\n                continue;\n            } else {\n                usleep(200000);  // 0.2 sec\n                if (pppoe_login(sockfd, dest_addr, &pppoe_counter, seed, sip, &login_first, &encrypt_mode, &encrypt_type)) {\n                    continue;\n                } else {\n                    login_first = 0;\n                    if (keepalive_2(sockfd, dest_addr, &keepalive_counter, &first, &encrypt_type)) {\n                        continue;\n                    } else {\n                        if (verbose_flag) {\n                            printf(\"PPPoE in loop.\\n\");\n                        }\n                        if (logging_flag) {\n                            logging(\"PPPoE in loop.\", NULL, 0);\n                        }\n                        sleep(10);\n                        continue;\n                    }\n                }\n            }\n        }\n    }\n\n    printf(\">>>>> Failed to keep in touch with server, exiting <<<<<\\n\\n\");\n    if (logging_flag) {\n        logging(\">>>>> Failed to keep in touch with server, exiting <<<<<\", NULL, 0);\n    }\n#ifdef WIN32\n    closesocket(sockfd);\n    WSACleanup();\n#else\n    close(sockfd);\n#endif\n    return 1;\n}\n\nvoid print_packet(char msg[10], unsigned char *packet, int length) {\n    printf(\"%s\", msg);\n    for (int i = 0; i < length; i++) {\n        printf(\"%02x\", packet[i]);\n    }\n    printf(\"\\n\");\n}\n\nvoid logging(char msg[10], unsigned char *packet, int length) {\n    FILE *ptr_file;\n    ptr_file = fopen(log_path, \"a\");\n\n    char *wday[] = {\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"};\n    time_t timep;\n    struct tm *p;\n    time(&timep);\n    p = localtime(&timep);\n    fprintf(ptr_file, \"[%04d/%02d/%02d %s %02d:%02d:%02d] \",\n            (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);\n\n    fprintf(ptr_file, \"%s\", msg);\n    for (int i = 0; i < length; i++) {\n        fprintf(ptr_file, \"%02x\", packet[i]);\n    }\n    fprintf(ptr_file, \"\\n\");\n\n    fclose(ptr_file);\n}\n\n#ifdef WIN32\nvoid get_lasterror(char *msg) {\n    char err_msg[256];\n    err_msg[0] = '\\0';\n    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,\n                  NULL,\n                  WSAGetLastError(),\n                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\n                  err_msg,\n                  sizeof(err_msg),\n                  NULL);\n    fprintf(stderr, \"%s: %s\", msg, err_msg);\n}\n#endif"
  },
  {
    "path": "auth.h",
    "content": "#ifndef AUTH_H_\n#define AUTH_H_\n\n#ifdef WIN32\n#include <winsock2.h>\n#else\n#include <netinet/in.h>\n#endif\n\nenum {\n    CHECK_MAC = 0x01,\n    SERVER_BUSY = 0x02,\n    WRONG_PASS = 0x03,\n    NOT_ENOUGH = 0x04,\n    FREEZE_UP = 0x05,\n    NOT_ON_THIS_IP = 0x07,\n    NOT_ON_THIS_MAC = 0x0B,\n    TOO_MUCH_IP = 0x14,\n    UPDATE_CLIENT = 0x15,\n    NOT_ON_THIS_IP_MAC = 0x16,\n    MUST_USE_DHCP = 0x17\n};\n\nint dhcp_challenge(int sockfd, struct sockaddr_in addr, unsigned char seed[]);\nint dhcp_login(int sockfd, struct sockaddr_in addr, unsigned char seed[], unsigned char auth_information[], int try_JLUversion);\nint pppoe_challenge(int sockfd, struct sockaddr_in addr, int *pppoe_counter, unsigned char seed[], unsigned char sip[], int *encrypt_mode);\nint pppoe_login(int sockfd, struct sockaddr_in addr, int *pppoe_counter, unsigned char seed[], unsigned char sip[], int *first, int *encrypt_mode, int *encrypt_type);\nint dogcom(int try_times);\nvoid print_packet(char msg[10], unsigned char *packet, int length);\nvoid logging(char msg[10], unsigned char *packet, int length);\nvoid get_lasterror(char *msg);\n\n#endif  // AUTH_H_"
  },
  {
    "path": "configparse.c",
    "content": "#include \"configparse.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"debug.h\"\n\nint verbose_flag = 0;\nint logging_flag = 0;\nint eapol_flag = 0;\nint eternal_flag = 0;\nchar *log_path;\nchar mode[10];\nchar bind_ip[20];\nstruct config drcom_config;\n\nstatic int read_d_config(char *buf, int size);\nstatic int read_p_config(char *buf, int size);\n\nint config_parse(char *filepath) {\n    FILE *ptr_file;\n    char buf[100];\n\n    ptr_file = fopen(filepath, \"r\");\n    if (!ptr_file) {\n        printf(\"Failed to read config file.\\n\");\n        exit(1);\n    }\n\n    while (fgets(buf, sizeof(buf), ptr_file)) {\n        if (strcmp(mode, \"dhcp\") == 0) {\n            read_d_config(buf, sizeof(buf));\n        } else if (strcmp(mode, \"pppoe\") == 0) {\n            read_p_config(buf, sizeof(buf));\n        }\n    }\n    if (verbose_flag) {\n        printf(\"\\n\\n\");\n    }\n    fclose(ptr_file);\n\n    return 0;\n}\n\nstatic int read_d_config(char *buf, int size) {\n    if (verbose_flag) {\n        printf(\"%s\", buf);\n    }\n\n    char *delim = \" ='\\r\\n\";\n    char *delim2 = \"\\\\x\";\n    char *key;\n    char *value;\n    if (strlen(key = strtok(buf, delim))) {\n        value = strtok(NULL, delim);\n    }\n    drcom_config.keepalive1_mod = 0;\n\n    if (strcmp(key, \"server\") == 0) {\n        strcpy(drcom_config.server, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.server));\n    } else if (strcmp(key, \"username\") == 0) {\n        strcpy(drcom_config.username, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.username));\n    } else if (strcmp(key, \"password\") == 0) {\n        strcpy(drcom_config.password, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.password));\n    } else if (strcmp(key, \"CONTROLCHECKSTATUS\") == 0) {\n        value = strtok(value, delim2);\n        sscanf(value, \"%02hhx\", &drcom_config.CONTROLCHECKSTATUS);\n        DEBUG_PRINT((\"[PARSER_DEBUG]0x%02x\\n\", drcom_config.CONTROLCHECKSTATUS));\n    } else if (strcmp(key, \"ADAPTERNUM\") == 0) {\n        value = strtok(value, delim2);\n        sscanf(value, \"%02hhx\", &drcom_config.ADAPTERNUM);\n        DEBUG_PRINT((\"[PARSER_DEBUG]0x%02x\\n\", drcom_config.ADAPTERNUM));\n    } else if (strcmp(key, \"host_ip\") == 0) {\n        strcpy(drcom_config.host_ip, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.host_ip));\n    } else if (strcmp(key, \"IPDOG\") == 0) {\n        value = strtok(value, delim2);\n        sscanf(value, \"%02hhx\", &drcom_config.IPDOG);\n        DEBUG_PRINT((\"[PARSER_DEBUG]0x%02x\\n\", drcom_config.IPDOG));\n    } else if (strcmp(key, \"host_name\") == 0) {\n        strcpy(drcom_config.host_name, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.host_name));\n    } else if (strcmp(key, \"PRIMARY_DNS\") == 0) {\n        strcpy(drcom_config.PRIMARY_DNS, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.PRIMARY_DNS));\n    } else if (strcmp(key, \"dhcp_server\") == 0) {\n        strcpy(drcom_config.dhcp_server, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.dhcp_server));\n    } else if (strcmp(key, \"AUTH_VERSION\") == 0) {\n        char *v1 = strtok(value, delim2);\n        char *v2 = strtok(NULL, delim2);\n        sscanf(v1, \"%02hhx\", v1);\n        sscanf(v2, \"%02hhx\", v2);\n        memcpy(&drcom_config.AUTH_VERSION[0], v1, 1);\n        memcpy(&drcom_config.AUTH_VERSION[1], v2, 1);\n        DEBUG_PRINT((\"[PARSER_DEBUG]0x%02x\\n\", drcom_config.AUTH_VERSION[0]));\n        DEBUG_PRINT((\"[PARSER_DEBUG]0x%02x\\n\", drcom_config.AUTH_VERSION[1]));\n    } else if (strcmp(key, \"mac\") == 0) {\n        char *delim3 = \"x\";\n        // strsep(&value, delim3);\n        value = strtok(value, delim3);\n        value = strtok(NULL, delim3);\n        sscanf(value, \"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx\",\n               &drcom_config.mac[0],\n               &drcom_config.mac[1],\n               &drcom_config.mac[2],\n               &drcom_config.mac[3],\n               &drcom_config.mac[4],\n               &drcom_config.mac[5]);\n#ifdef DEBUG\n        printf(\"[PARSER_DEBUG]0x\");\n        for (int i = 0; i < 6; i++) {\n            printf(\"%02x\", drcom_config.mac[i]);\n        }\n        printf(\"\\n\");\n#endif\n    } else if (strcmp(key, \"host_os\") == 0) {\n        strcpy(drcom_config.host_os, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.host_os));\n    } else if (strcmp(key, \"KEEP_ALIVE_VERSION\") == 0) {\n        char *v1 = strtok(value, delim2);\n        char *v2 = strtok(NULL, delim2);\n        sscanf(v1, \"%02hhx\", v1);\n        sscanf(v2, \"%02hhx\", v2);\n        memcpy(&drcom_config.KEEP_ALIVE_VERSION[0], v1, 1);\n        memcpy(&drcom_config.KEEP_ALIVE_VERSION[1], v2, 1);\n        DEBUG_PRINT((\"[PARSER_DEBUG]0x%02x\\n\", drcom_config.KEEP_ALIVE_VERSION[0]));\n        DEBUG_PRINT((\"[PARSER_DEBUG]0x%02x\\n\", drcom_config.KEEP_ALIVE_VERSION[1]));\n    } else if (strcmp(key, \"ror_version\") == 0) {\n        if (strcmp(value, \"True\") == 0) {\n            drcom_config.ror_version = 1;\n        } else {\n            drcom_config.ror_version = 0;\n        }\n        DEBUG_PRINT((\"\\n[PARSER_DEBUG]\\n%d\\n\", drcom_config.ror_version));\n    } else if (strcmp(key, \"keepalive1_mod\") == 0) {\n        if (strcmp(value, \"True\") == 0) {\n            drcom_config.keepalive1_mod = 1;\n        } else {\n            drcom_config.keepalive1_mod = 0;\n        }\n        DEBUG_PRINT((\"\\n[PARSER_DEBUG]\\n%d\\n\", drcom_config.keepalive1_mod));\n    } else {\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic int read_p_config(char *buf, int size) {\n    if (verbose_flag) {\n        printf(\"%s\", buf);\n    }\n\n    char *delim = \" ='\\r\\n\";\n    char *delim2 = \"\\\\x\";\n    char *key;\n    char *value;\n    if (strlen(key = strtok(buf, delim))) {\n        value = strtok(NULL, delim);\n    }\n\n    if (strcmp(key, \"server\") == 0) {\n        strcpy(drcom_config.server, value);\n        DEBUG_PRINT((\"[PARSER_DEBUG]%s\\n\", drcom_config.server));\n    } else if (strcmp(key, \"pppoe_flag\") == 0) {\n        value = strtok(value, delim2);\n        sscanf(value, \"%02hhx\", &drcom_config.pppoe_flag);\n        DEBUG_PRINT((\"[PARSER_DEBUG]0x%02x\\n\", drcom_config.pppoe_flag));\n    } else if (strcmp(key, \"keep_alive2_flag\") == 0) {\n        value = strtok(value, delim2);\n        sscanf(value, \"%02hhx\", &drcom_config.keep_alive2_flag);\n        DEBUG_PRINT((\"\\n[PARSER_DEBUG]0x%02x\\n\", drcom_config.keep_alive2_flag));\n    } else {\n        return 1;\n    }\n\n    return 0;\n}"
  },
  {
    "path": "configparse.h",
    "content": "#ifndef CONFIGPARSE_H_\n#define CONFIGPARSE_H_\n\nstruct config {\n    char server[20];\n    char username[36];\n    char password[20];\n    unsigned char CONTROLCHECKSTATUS;\n    unsigned char ADAPTERNUM;\n    char host_ip[20];\n    unsigned char IPDOG;\n    char host_name[20];\n    char PRIMARY_DNS[20];\n    char dhcp_server[20];\n    unsigned char AUTH_VERSION[2];\n    unsigned char mac[6];\n    char host_os[20];\n    unsigned char KEEP_ALIVE_VERSION[2];\n    int ror_version;\n    int keepalive1_mod;\n    unsigned char pppoe_flag;\n    unsigned char keep_alive2_flag; /* abandoned */\n};\n\nextern struct config drcom_config;\nextern int verbose_flag;\nextern int logging_flag;\nextern int eapol_flag;\nextern int eternal_flag;\nextern char *log_path;\nextern char mode[10];\nextern char bind_ip[20];\n\nint config_parse(char *filepath);\n\n#endif  // CONFIGPARSE_H_"
  },
  {
    "path": "daemon.c",
    "content": "#ifdef linux\n\n#include <fcntl.h>\n#include <signal.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/stat.h>\n#include <unistd.h>\n#include \"debug.h\"\n\nint daemon_flag = 0;\nint pid_file_handle;\n\nvoid kill_daemon() {\n    close(pid_file_handle);\n    remove(\"/tmp/dogcom.pid\");\n}\n\nvoid signal_handler(int signal) {\n    switch (signal) {\n        case SIGHUP:\n            break;\n        case SIGINT:\n            break;\n        case SIGTERM:\n            kill_daemon();\n            exit(0);\n            break;\n        default:\n            break;\n    }\n}\n\nvoid daemonise() {\n    pid_t pid;\n    struct sigaction sig_action;\n    sigset_t sigset;\n\n    pid = fork();\n    if (pid < 0) {\n        printf(\"Fork failed!\\n\");\n        exit(1);\n    } else if (pid > 0) {\n        DEBUG_PRINT((\"PID is %d.\\n\", pid));\n        exit(0);\n    }\n    if (setsid() < 0) {\n        printf(\"Setsid failed!\\n\");\n        exit(1);\n    }\n\n    sigemptyset(&sigset);\n    sigaddset(&sigset, SIGCHLD);\n    sigaddset(&sigset, SIGTSTP);\n    sigaddset(&sigset, SIGTTOU);\n    sigaddset(&sigset, SIGTTIN);\n    sigprocmask(SIG_BLOCK, &sigset, NULL);\n    sig_action.sa_handler = signal_handler;\n    sigemptyset(&sig_action.sa_mask);\n    sig_action.sa_flags = 0;\n    sigaction(SIGHUP, &sig_action, NULL);\n    sigaction(SIGTERM, &sig_action, NULL);\n    sigaction(SIGINT, &sig_action, NULL);\n\n    pid = fork();\n    if (pid < 0) {\n        printf(\"Fork failed!\\n\");\n        exit(1);\n    } else if (pid > 0) {\n        DEBUG_PRINT((\"PID is %d.\\n\", pid));\n        exit(0);\n    }\n\n    chdir(\"/tmp/\");\n    umask(027);\n\n    close(STDIN_FILENO);\n    close(STDOUT_FILENO);\n    close(STDERR_FILENO);\n    open(\"/dev/null\", O_RDONLY);\n    open(\"/dev/null\", O_WRONLY);\n    open(\"/dev/null\", O_RDWR);\n\n    pid_file_handle = open(\"/tmp/dogcom.pid\", O_RDWR | O_CREAT, 0600);\n    if (pid_file_handle < 0) {\n        exit(1);\n    }\n    if (lockf(pid_file_handle, F_TLOCK, 0) < 0) {\n        exit(1);\n    }\n\n    char spid[10];\n    sprintf(spid, \"%d\\n\", getpid());\n    write(pid_file_handle, spid, strlen(spid));\n}\n\n#endif"
  },
  {
    "path": "daemon.h",
    "content": "#ifndef DAEMON_H_\n#define DAEMON_H_\n\nvoid kill_daemon();\nvoid signal_handler(int signal);\nvoid daemonise();\n\nextern int daemon_flag;\nextern int pid_file_handle;\n\n#endif  // DAEMON_H_"
  },
  {
    "path": "debug.h",
    "content": "#ifdef DEBUG\n#define DEBUG_PRINT(s) printf s\n#else\n#define DEBUG_PRINT(s) \\\n    do {               \\\n    } while (0)\n#endif"
  },
  {
    "path": "eapol.c",
    "content": "#ifdef linux\n\n#include \"eapol.h\"\n#include \"libs/common.h\"\n#include \"libs/md5.h\"\n\n#include <arpa/inet.h>\n#include <net/ethernet.h>\n#include <net/if.h>\n#include <netinet/if_ether.h>\n#include <netpacket/packet.h>\n#include <sys/ioctl.h>\n#include <sys/socket.h>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <unistd.h>\n\n#include <errno.h>\n#include <signal.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <time.h>\n\n#define BUFF_LEN (512)\n\nstatic uchar client_mac[ETH_ALEN];\n\nstatic uchar sendbuff[BUFF_LEN];\nstatic uchar recvbuff[BUFF_LEN];\nstatic char ifname[IFNAMSIZ] = \"eth0\";\nstatic ethII_t *sendethii, *recvethii;\nstatic eapol_t *sendeapol, *recveapol;\nstatic eap_t *sendeap, *recveap;\nstatic eapbody_t *sendeapbody, *recveapbody;\n\nstatic char _uname[UNAME_LEN];\nstatic char _pwd[PWD_LEN];\nstatic int pwdlen;\n\nstatic int eap_keep_alive(int skfd, struct sockaddr const *skaddr);\nstatic int eap_md5_clg(int skfd, struct sockaddr const *skaddr);\nstatic int eap_res_identity(int skfd, struct sockaddr const *skaddr);\nstatic int eapol_init(int *skfd, struct sockaddr *skaddr);\nstatic int eapol_start(int skfd, struct sockaddr const *skaddr);\nstatic int eapol_logoff(int skfd, struct sockaddr const *skaddr);\nstatic int filte_req_identity(int skfd, struct sockaddr const *skaddr);\nstatic int filte_req_md5clg(int skfd, struct sockaddr const *skaddr);\nstatic int filte_success(int skfd, struct sockaddr const *skaddr);\nstatic int eap_daemon(int skfd, struct sockaddr const *skaddr);\n\n/*\n * 初始化缓存区，生产套接字和地址接口信息\n * skfd: 被初始化的socket\n * skaddr: 被初始化地址接口信息\n * @return: 0: 成功\n *          -1: 初始化套接字失败\n *          -2: 初始化地址信息失败\n */\nstatic int eapol_init(int *skfd, struct sockaddr *skaddr) {\n    struct ifreq ifr;\n    struct sockaddr_ll *skllp = (struct sockaddr_ll *)skaddr;\n    sendethii = (ethII_t *)sendbuff;\n    sendeapol = (eapol_t *)((uchar *)sendethii + sizeof(ethII_t));\n    sendeap = (eap_t *)((uchar *)sendeapol + sizeof(eapol_t));\n    sendeapbody = (eapbody_t *)((uchar *)sendeap + sizeof(eap_t));\n    recvethii = (ethII_t *)recvbuff;\n    recveapol = (eapol_t *)((uchar *)recvethii + sizeof(ethII_t));\n    recveap = (eap_t *)((uchar *)recveapol + sizeof(eapol_t));\n    recveapbody = (eapbody_t *)((uchar *)recveap + sizeof(eap_t));\n\n    if (-1 == (*skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)))) {\n        perror(\"Socket\");\n        return -1;\n    }\n    /* 先假定就是eth0接口 */\n    memset(skaddr, 0, sizeof(struct sockaddr_ll));\n    memset(&ifr, 0, sizeof(struct ifreq));\n    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);\n    if (-1 == ioctl(*skfd, SIOCGIFINDEX, &ifr)) {\n        perror(\"Get index\");\n        goto addr_err;\n    }\n    skllp->sll_ifindex = ifr.ifr_ifindex;\n    _D(\"%s's index: %d\\n\", ifname, skllp->sll_ifindex);\n    if (-1 == ioctl(*skfd, SIOCGIFHWADDR, &ifr)) {\n        perror(\"Get MAC\");\n        goto addr_err;\n    }\n    memcpy(client_mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);\n    _D(\"%s's MAC: %02X-%02X-%02X-%02X-%02X-%02X\\n\", ifname,\n       client_mac[0], client_mac[1], client_mac[2],\n       client_mac[3], client_mac[4], client_mac[5]);\n    skllp->sll_family = PF_PACKET;\n    /*skllp->sll_protocol = ETH_P_ARP;*/\n    /*skllp->sll_ifindex = ? 已给出 */\n    skllp->sll_hatype = ARPHRD_ETHER;\n    skllp->sll_pkttype = PACKET_HOST;\n    skllp->sll_halen = ETH_ALEN;\n    return 0;\n\naddr_err:\n    close(*skfd);\n    return -2;\n}\n\n/*\n * 过滤得到eap-request-identity包\n * @return: 0: 成功获取\n *          -1: 超时\n */\nstatic int filte_req_identity(int skfd, struct sockaddr const *skaddr) {\n    (void)skaddr;\n    int stime = time((time_t *)NULL);\n    for (; difftime(time((time_t *)NULL), stime) <= TIMEOUT;) {\n        /* TODO 看下能不能只接受某类包，包过滤 */\n        recvfrom(skfd, recvbuff, BUFF_LEN, 0, NULL, NULL);\n        /* eap包且是request */\n        if (recvethii->type == htons(ETHII_8021X) && mac_equal(recvethii->dst_mac, client_mac) && recveapol->type == EAPOL_PACKET && recveap->code == EAP_CODE_REQ && recveap->type == EAP_TYPE_IDEN) {\n            return 0;\n        }\n    }\n    return -1;\n}\n/*\n * 过滤得到eap-request-md5clg包\n * @return: 0: 成功获取\n *          -1: 超时\n *          -2: 服务器中止登录，用户名不存在\n */\nstatic int filte_req_md5clg(int skfd, struct sockaddr const *skaddr) {\n    (void)skaddr;\n    int stime = time((time_t *)NULL);\n    for (; difftime(time((time_t *)NULL), stime) <= TIMEOUT;) {\n        recvfrom(skfd, recvbuff, BUFF_LEN, 0, NULL, NULL);\n        /* 是request且是eap-request-md5clg */\n        if (recvethii->type == htons(ETHII_8021X) && mac_equal(recvethii->dst_mac, client_mac) && recveapol->type == EAPOL_PACKET) {\n            if (recveap->code == EAP_CODE_REQ && recveap->type == EAP_TYPE_MD5) {\n#ifdef DEBUG\n                _M(\"id: %d\\n\", sendeap->id);\n                _M(\"md5: \");\n                int i;\n                for (i = 0; i < recveapbody->md5size; ++i)\n                    _M(\"%.2x\", recveapbody->md5value[i]);\n                _M(\"\\n\");\n                _M(\"ex-md5: \");\n                for (i = 0; i < ntohs(recveap->len) - recveapbody->md5size - 2; ++i)\n                    _M(\"%.2x\", recveapbody->md5exdata[i]);\n                _M(\"\\n\");\n#endif\n                return 0;\n            } else if (recveap->id == sendeap->id && recveap->code == EAP_CODE_FAIL) {\n                _D(\"id: %d fail.\\n\", sendeap->id);\n                return -2;\n            }\n        }\n    }\n    return -1;\n}\n/*\n * 过滤得到登录成功包\n * @return: 0: 成功获取\n *          -1: 超时\n *          -2: 服务器中止登录，密码错误吧\n */\nstatic int filte_success(int skfd, struct sockaddr const *skaddr) {\n    (void)skaddr;\n    int stime = time((time_t *)NULL);\n    for (; difftime(time((time_t *)NULL), stime) <= TIMEOUT;) {\n        recvfrom(skfd, recvbuff, BUFF_LEN, 0, NULL, NULL);\n        if (recvethii->type == htons(ETHII_8021X) && mac_equal(recvethii->dst_mac, client_mac) && recveapol->type == EAPOL_PACKET) {\n            if (recveap->id == sendeap->id && recveap->code == EAP_CODE_SUCS) {\n                _D(\"id: %d login success.\\n\", sendeap->id);\n                return 0;\n            } else if (recveap->id == sendeap->id && recveap->code == EAP_CODE_FAIL) {\n                _D(\"id: %d fail.\\n\", sendeap->id);\n                return -2;\n            }\n        }\n    }\n    return -1;\n}\n/*\n * 广播发送eapol-start\n */\nstatic int eapol_start(int skfd, struct sockaddr const *skaddr) {\n    /* 这里采用eap标记的组播mac地址，也许采用广播也可以吧 */\n    uchar broadcast_mac[ETH_ALEN] = {\n        //\t\t0x01, 0x80, 0xc2, 0x00, 0x00, 0x03,\n        0xff,\n        0xff,\n        0xff,\n        0xff,\n        0xff,\n        0xff,\n    };\n    memcpy(sendethii->dst_mac, broadcast_mac, ETH_ALEN);\n    memcpy(sendethii->src_mac, client_mac, ETH_ALEN);\n    sendethii->type = htons(ETHII_8021X);\n    sendeapol->ver = EAPOL_VER;\n    sendeapol->type = EAPOL_START;\n    sendeapol->len = 0x0;\n    sendto(skfd, sendbuff, ETH_ALEN * 2 + 6, 0, skaddr, sizeof(struct sockaddr_ll));\n    return 0;\n}\n/* 退出登录 */\nstatic int eapol_logoff(int skfd, struct sockaddr const *skaddr) {\n    uchar broadcast_mac[ETH_ALEN] = {\n        //\t\t0x01, 0x80, 0xc2, 0x00, 0x00, 0x03,\n        0xff,\n        0xff,\n        0xff,\n        0xff,\n        0xff,\n        0xff,\n    };\n    memcpy(sendethii->dst_mac, broadcast_mac, ETH_ALEN);\n    memcpy(sendethii->src_mac, client_mac, ETH_ALEN);\n    sendethii->type = htons(ETHII_8021X);\n    sendeapol->ver = EAPOL_VER;\n    sendeapol->type = EAPOL_LOGOFF;\n    sendeapol->len = 0x0;\n    sendeap->id = EAPOL_LOGOFF_ID;\n    sendto(skfd, sendbuff, ETH_ALEN * 2 + 6, 0, skaddr, sizeof(struct sockaddr_ll));\n    return 0;\n}\n/* 回应request-identity */\nstatic int eap_res_identity(int skfd, struct sockaddr const *skaddr) {\n    memcpy(sendethii->dst_mac, recvethii->src_mac, ETH_ALEN);\n    sendeapol->type = EAPOL_PACKET;\n    sendeapol->len = htons(sizeof(eap_t) + sizeof(eapbody_t));\n    sendeap->code = EAP_CODE_RES;\n    sendeap->id = recveap->id;\n    sendeap->len = htons(sizeof(eapbody_t));\n    sendeap->type = EAP_TYPE_IDEN;\n    strncpy((char *)sendeapbody->identity, _uname, UNAME_LEN);\n    sendto(skfd, sendbuff, ETH_ALEN * 2 + 6 + 5 + sizeof(eapbody_t),\n           0, skaddr, sizeof(struct sockaddr_ll));\n    return 0;\n}\n/* 回应md5clg */\nstatic int eap_md5_clg(int skfd, struct sockaddr const *skaddr) {\n    uchar md5buff[BUFF_LEN];\n    sendeap->id = recveap->id;\n    sendeap->len = htons(sizeof(eapbody_t));\n    sendeap->type = EAP_TYPE_MD5;\n    sendeapbody->md5size = recveapbody->md5size;\n    memcpy(md5buff, &sendeap->id, 1);\n    memcpy(md5buff + 1, _pwd, pwdlen);\n    memcpy(md5buff + 1 + pwdlen, recveapbody->md5value, recveapbody->md5size);\n    MD5(md5buff, 1 + pwdlen + recveapbody->md5size, sendeapbody->md5value);\n    memcpy((char *)sendeapbody->md5exdata, _uname, strlen(_uname));\n    sendto(skfd, sendbuff, ETH_ALEN * 2 + 6 + 5 + sizeof(eapbody_t),\n           0, skaddr, sizeof(struct sockaddr_ll));\n    return 0;\n}\n\n/*\n * 保持在线\n * eap心跳包\n * 某些eap实现需要心跳或多次认证\n * 目前有些服务器会有如下特征\n * 每一分钟，服务端发送一个request-identity包来判断是否在线\n */\nstatic int eap_keep_alive(int skfd, struct sockaddr const *skaddr) {\n    int status;\n    time_t stime, etime;\n    /* EAP_KPALV_TIMEOUT时间内已经不再有心跳包，我们认为服务器不再需要心跳包了 */\n    //for (; difftime(time((time_t*)NULL), stime) <= EAP_KPALV_TIMEOUT; ) {\n    stime = time((time_t *)NULL);\n    for (;;) {\n        status = filte_req_identity(skfd, skaddr);\n        //_D(\"%s: [EAP:KPALV] get status: %d\\n\", format_time(), status);\n        if (0 == status) {\n            etime = time((time_t *)NULL);\n            _D(\"dtime: %fs\\n\", difftime(etime, stime));\n            if (difftime(etime, stime) <= 10) {\n                stime = time((time_t *)NULL);\n                continue;\n            }\n            stime = time((time_t *)NULL);\n#if 0\n#ifdef DEBUG\n\t\t\t_D(\"[KPALV] get eap request identity:\\n\");\n\t\t\t_D(\"dst<-src: %2X:%2X:%2X:%2X:%2X:%2X <- %2X:%2X:%2X:%2X:%2X:%2X\\n\",\n\t\t\t\t\trecvethii->dst_mac[0], recvethii->dst_mac[1], recvethii->dst_mac[2],\n\t\t\t\t\trecvethii->dst_mac[3], recvethii->dst_mac[4], recvethii->dst_mac[5],\n\t\t\t\t\trecvethii->src_mac[0], recvethii->src_mac[1], recvethii->src_mac[2],\n\t\t\t\t\trecvethii->src_mac[3], recvethii->src_mac[4], recvethii->src_mac[5]);\n\t\t\t_D(\"ethII.type: 0x%4x\\n\", ntohs(recvethii->type));\n\t\t\t_D(\"recveapol.type: %s\\n\", recveapol->type==EAPOL_PACKET?\"EAPOL_PACKET\":\"UNKNOWN\");\n\t\t\t_D(\"recveapol.len: %d\\n\", ntohs(recveapol->len));\n\t\t\t_D(\"recveap.code: %s\\n\", recveap->code==EAP_CODE_REQ?\"EAP_CODE_REQ\":\"UNKNOWN\");\n\t\t\t_D(\"recveap.id: %d\\n\", recveap->id);\n\t\t\t_D(\"recveap.type: %s\\n\", recveap->type==EAP_TYPE_IDEN?\"EAP_TYPE_IDEN\":\"UNKNOWN\");\n#endif\n#endif\n            _M(\"%s: [EAP:KPALV] get a request-identity\\n\", format_time());\n            eap_res_identity(skfd, skaddr);\n#if 0\n#ifdef DEBUG\n\t\t\t_D(\"[EAP:KPALV] send eap response identity:\\n\");\n\t\t\t_D(\"dst<-src: %2X:%2X:%2X:%2X:%2X:%2X <- %2X:%2X:%2X:%2X:%2X:%2X\\n\",\n\t\t\t\t\tsendethii->dst_mac[0], sendethii->dst_mac[1], sendethii->dst_mac[2],\n\t\t\t\t\tsendethii->dst_mac[3], sendethii->dst_mac[4], sendethii->dst_mac[5],\n\t\t\t\t\tsendethii->src_mac[0], sendethii->src_mac[1], sendethii->src_mac[2],\n\t\t\t\t\tsendethii->src_mac[3], sendethii->src_mac[4], sendethii->src_mac[5]);\n\t\t\t_D(\"ethII.type: 0x%4x\\n\", ntohs(sendethii->type));\n\t\t\t_D(\"sendeapol.type: %s\\n\", sendeapol->type==EAPOL_PACKET?\"EAPOL_PACKET\":\"UNKNOWN\");\n\t\t\t_D(\"sendeapol.len: %d\\n\", ntohs(sendeapol->len));\n\t\t\t_D(\"sendeap.code: %s\\n\", sendeap->code==EAP_CODE_RES?\"EAP_CODE_RES\":\"UNKNOWN\");\n\t\t\t_D(\"sendeap.id: %d\\n\", sendeap->id);\n\t\t\t_D(\"sendeap.type: %s\\n\", sendeap->type==EAP_TYPE_IDEN?\"EAP_TYPE_IDEN\":\"UNKNOWN\");\n\t\t\t_D(\"sendeapbody.identity: %s\\n\", sendeapbody->identity);\n#endif\n#endif\n        }\n        status = -1;\n    }\n    return 0;\n}\n/*\n * 后台心跳进程\n * @return: 0, 正常运行\n * \t\t\t-1, 运行失败\n */\nstatic int eap_daemon(int skfd, struct sockaddr const *skaddr) {\n    /* 如果存在原来的keep alive进程，就干掉他 */\n#define PID_FILE \"/tmp/cwnu-drcom-eap.pid\"\n    FILE *kpalvfd = fopen(PID_FILE, \"r+\");\n    if (NULL == kpalvfd) {\n        _M(\"[EAP:KPALV] No process pidfile. %s: %s\\n\", PID_FILE, strerror(errno));\n        kpalvfd = fopen(PID_FILE, \"w+\"); /* 不存在，创建 */\n        if (NULL == kpalvfd) {\n            _M(\"[EAP:KPALV] Detect pid file eror(%s)! quit!\\n\", strerror(errno));\n            return -1;\n        }\n    }\n    pid_t oldpid;\n\n    fseek(kpalvfd, 0L, SEEK_SET);\n    if ((1 == fscanf(kpalvfd, \"%d\", (int *)&oldpid)) && (oldpid != (pid_t)-1)) {\n        _D(\"oldkpalv pid: %d\\n\", oldpid);\n        kill(oldpid, SIGKILL);\n    }\n    setsid();\n    if (0 != chdir(\"/\"))\n        _M(\"[EAP:KPALV:WARN] %s\\n\", strerror(errno));\n    umask(0);\n    /* 在/tmp下写入自己(keep alive)pid */\n    pid_t curpid = getpid();\n    _D(\"kpalv curpid: %d\\n\", curpid);\n    /*\n\t * if (0 != ftruncate(fileno(kpalvfd), 0))\n\t * 这个写法有时不能正常截断文件，截断后前面有\\0？\n\t */\n    if (NULL == (kpalvfd = freopen(PID_FILE, \"w+\", kpalvfd)))\n        _M(\"[EAP:KPALV:WARN] truncat pidfile '%s': %s\\n\", PID_FILE, strerror(errno));\n    fprintf(kpalvfd, \"%d\", curpid);\n    fflush(kpalvfd);\n    if (0 == eap_keep_alive(skfd, skaddr)) {\n        _M(\"%s: [EAP:KPALV] Server maybe not need keep alive paket.\\n\", format_time());\n        _M(\"%s: [EAP:KPALV] Now, keep alive process quit!\\n\", format_time());\n    }\n    if (NULL == (kpalvfd = freopen(PID_FILE, \"w+\", kpalvfd)))\n        _M(\"[EAP:KPALV:WARN] truncat pidfile '%s': %s\\n\", PID_FILE, strerror(errno));\n    fprintf(kpalvfd, \"-1\"); /* 写入-1表示已经离开 */\n    fflush(kpalvfd);\n    fclose(kpalvfd);\n\n    return 0;\n}\n\n/*\n * eap认证\n * uname: 用户名\n * pwd: 密码\n * @return: 0: 成功\n *          1: 用户不存在\n *          2: 密码错误\n *          3: 其他超时\n *          4: 服务器拒绝请求登录\n *          -1: 没有找到合适网络接口\n *          -2: 没有找到服务器\n */\nint eaplogin(char const *uname, char const *pwd) {\n    int i;\n    int state;\n    int skfd;\n    struct sockaddr_ll ll;\n\n    _M(\"Use user '%s' to login...\\n\", uname);\n    _M(\"[EAP:0] Initilize interface...\\n\");\n    strncpy(_uname, uname, UNAME_LEN);\n    strncpy(_pwd, pwd, PWD_LEN);\n    pwdlen = strlen(_pwd);\n    if (0 != eapol_init(&skfd, (struct sockaddr *)&ll))\n        return -1;\n    /* 无论如何先请求一下下线 */\n    eapol_logoff(skfd, (struct sockaddr *)&ll);\n    /* eap-start */\n    _M(\"[EAP:1] Send eap-start...\\n\");\n    for (i = 0; i < TRY_TIMES; ++i) {\n        eapol_start(skfd, (struct sockaddr *)&ll);\n        if (0 == filte_req_identity(skfd, (struct sockaddr *)&ll))\n            break;\n        _M(\" [EAP:1] %dth Try send eap-start...\\n\", i + 1);\n    }\n    if (i >= TRY_TIMES) goto _timeout;\n\n    /* response-identity */\n    _M(\"[EAP:2] Send response-identity...\\n\");\n    for (i = 0; i < TRY_TIMES; ++i) {\n        eap_res_identity(skfd, (struct sockaddr *)&ll);\n        state = filte_req_md5clg(skfd, (struct sockaddr *)&ll);\n        if (0 == state)\n            break;\n        else if (-2 == state)\n            goto _no_uname;\n        _M(\" [EAP:2] %dth Try send response-identity...\\n\", i + 1);\n    }\n    if (i >= TRY_TIMES) goto _timeout;\n\n    /* response-md5clg */\n    _M(\"[EAP:3] Send response-md5clg...\\n\");\n    for (i = 0; i < TRY_TIMES; ++i) {\n        eap_md5_clg(skfd, (struct sockaddr *)&ll);\n        state = filte_success(skfd, (struct sockaddr *)&ll);\n        if (0 == state) {\n            _M(\"[EAP:4] Login success.\\n\");\n            break; /* 登录成功 */\n        } else if (-2 == state)\n            goto _pwd_err;\n        _M(\" [EAP:3] %dth Try send response-md5clg...\\n\", i + 1);\n    }\n    if (i >= TRY_TIMES) goto _timeout;\n\n    /* 登录成功，生成心跳进程 */\n    switch (fork()) {\n        case 0:\n            if (0 != eap_daemon(skfd, (struct sockaddr *)&ll)) {\n                _M(\"[EAP:ERROR] Create daemon process to keep alive error!\\n\");\n                close(skfd);\n                exit(1);\n            }\n            exit(0);\n            break;\n        case -1:\n            _M(\"[EAP:WARN] Cant create daemon, maybe `OFFLINE` after soon.\\n\");\n    }\n    close(skfd);\n    return 0;\n\n_timeout:\n    _M(\"[EAP:ERROR] Not server in range.\\n\");\n    close(skfd);\n    return -2;\n_no_uname:\n    _M(\"[EAP:ERROR] No this user(%s).\\n\", uname);\n    close(skfd);\n    return 1;\n_pwd_err:\n    _M(\"[EAP:ERROR] The server refuse to login. Password error.\\n\");\n    close(skfd);\n    return 4;\n}\n\nint eaplogoff(void) {\n    int skfd;\n    struct sockaddr_ll ll;\n    int state;\n    int i;\n\n    _M(\"[EAP:0] Initilize interface...\\n\");\n    if (0 != eapol_init(&skfd, (struct sockaddr *)&ll))\n        return -1;\n    _M(\"[EAP:1] Requset logoff...\\n\");\n    for (i = 0; i < TRY_TIMES; ++i) {\n        eapol_logoff(skfd, (struct sockaddr *)&ll);\n        state = filte_success(skfd, (struct sockaddr *)&ll);\n        if (-2 == state) {\n            _M(\"[EAP:2] Logoff!\\n\");\n            return 0;\n        }\n        _M(\" [EAP:1] %dth Try Requset logoff...\\n\", i + 1);\n    }\n    _M(\"[EAP:ERROR] Not server in range. or You were logoff.\\n\");\n    return -1;\n}\n\nint eaprefresh(char const *uname, char const *pwd) {\n    return eaplogin(uname, pwd);\n}\n\n/* 设置ifname */\nvoid setifname(char const *_ifname) {\n    strncpy(ifname, _ifname, IFNAMSIZ);\n}\n\n#endif"
  },
  {
    "path": "eapol.h",
    "content": "#ifndef EAPOL_H__\n#define EAPOL_H__\n\n#include \"libs/common.h\"\n\n#define IDEN_LEN UNAME_LEN\n\n#define TRY_TIMES (3)\n/* 每次请求超过TIMEOUT秒，就重新请求一次 */\n#define TIMEOUT (3)\n/* eap 在EAP_KPALV_TIMEOUT秒内没有回应，认为不需要心跳 */\n#define EAP_KPALV_TIMEOUT (420) /* 7分钟 */\n\n/* ethii层取0x888e表示上层是8021.x */\n#define ETHII_8021X (0x888e)\n\n#define EAPOL_VER (0x01)\n#define EAPOL_PACKET (0x00)\n#define EAPOL_START (0x01)\n#define EAPOL_LOGOFF (0x02)\n/* 貌似请求下线的id都是这个 */\n#define EAPOL_LOGOFF_ID (255)\n\n#define EAP_CODE_REQ (0x01)\n#define EAP_CODE_RES (0x02)\n#define EAP_CODE_SUCS (0x03)\n#define EAP_CODE_FAIL (0x04)\n#define EAP_TYPE_IDEN (0x01)\n#define EAP_TYPE_MD5 (0x04)\n\n#pragma pack(1)\n/* ethii 帧 */\n/* 其实这个和struct ether_header是一样的结构 */\ntypedef struct {\n    uchar dst_mac[ETH_ALEN];\n    uchar src_mac[ETH_ALEN];\n    uint16 type; /* 取值0x888e，表明是8021.x */\n} ethII_t;\n/* eapol 帧 */\ntypedef struct {\n    uchar ver; /* 取值0x01 */\n    /*\n     * 0x00: eapol-packet\n     * 0x01: eapol-start\n     * 0x02: eapol-logoff\n     */\n    uchar type;\n    uint16 len;\n} eapol_t;\n/* eap报文头 */\ntypedef struct {\n    /*\n     * 0x01: request\n     * 0x02: response\n     * 0x03: success\n     * 0x04: failure\n     */\n    uchar code;\n    uchar id;\n    uint16 len;\n    /*\n     * 0x01: identity\n     * 0x04: md5-challenge\n     */\n    uchar type;\n} eap_t;\n/* 报文体 */\n#define MD5_SIZE 16\n#define STUFF_LEN (64)\ntypedef union {\n    uchar identity[IDEN_LEN];\n    struct {\n        uchar _size;\n        uchar _md5value[MD5_SIZE];\n        uchar _exdata[STUFF_LEN];\n    } md5clg;\n} eapbody_t;\n#define md5size md5clg._size\n#define md5value md5clg._md5value\n#define md5exdata md5clg._exdata\n#pragma pack()\n\n/*\n * eap认证\n * uname: 用户名\n * pwd: 密码\n * @return: 0: 成功\n *          1: 用户不存在\n *          2: 密码错误\n *          3: 其他超时\n *          4: 服务器拒绝请求登录\n *          -1: 没有找到合适网络接口\n *          -2: 没有找到服务器\n */\nextern int eaplogin(char const *uname, char const *pwd);\n/*\n * eap下线\n */\nextern int eaplogoff(void);\n/*\n * eap重新登录\n */\nextern int eaprefresh(char const *uname, char const *pwd);\n/*\n * 用来设置ifname\n */\nextern void setifname(char const *ifname);\n// #ifdef WIN32\n/*\n * 由于windows下实现进程的特殊性，这里把eap_daemon导出给main_cli使用\n * ifname: 心跳的物理接口名字\n * @return: 0: keep alive 进程正常退出，也许并不需要心跳进程\n *         !0: 错误原因导致keep alive 进程退出，也许是没法创建进程\n */\n// extern int eap_daemon(char const *ifname);\n// #endif /* WINDOWS */\n#undef IDEN_LEN\n\n#endif\n"
  },
  {
    "path": "keepalive.c",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#ifdef WIN32\n#include <winsock2.h>\ntypedef int socklen_t;\n#else\n#include <netinet/in.h>\n#include <sys/socket.h>\n#endif\n\n#include \"auth.h\"\n#include \"configparse.h\"\n#include \"debug.h\"\n#include \"keepalive.h\"\n#include \"libs/md4.h\"\n#include \"libs/md5.h\"\n#include \"libs/sha1.h\"\n\nint keepalive_1(int sockfd, struct sockaddr_in addr, unsigned char seed[], unsigned char auth_information[]) {\n    if (drcom_config.keepalive1_mod) {\n        unsigned char keepalive_1_packet1[8] = {0x07, 0x01, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00};\n        unsigned char recv_packet1[1024], keepalive_1_packet2[38], recv_packet2[1024];\n        memset(keepalive_1_packet2, 0, 38);\n        sendto(sockfd, keepalive_1_packet1, 8, 0, (struct sockaddr *)&addr, sizeof(addr));\n        if (verbose_flag) {\n            print_packet(\"[Keepalive1_packet1 sent] \", keepalive_1_packet1, 8);\n        }\n        if (logging_flag) {\n            logging(\"[Keepalive1_packet1 sent] \", keepalive_1_packet1, 8);\n        }\n#ifdef TEST\n        printf(\"[TEST MODE]IN TEST MODE, PASS\\n\");\n        return 0;\n#endif\n        socklen_t addrlen = sizeof(addr);\n        while (1) {\n            if (recvfrom(sockfd, recv_packet1, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n                get_lasterror(\"Failed to recv data\");\n#else\n                perror(\"Failed to recv data\");\n#endif\n                return 1;\n            } else {\n                if (verbose_flag) {\n                    print_packet(\"[Keepalive1 challenge_recv] \", recv_packet1, 100);\n                }\n                if (logging_flag) {\n                    logging(\"[Keepalive1 challenge_recv] \", recv_packet1, 100);\n                }\n\n                if (recv_packet1[0] == 0x07) {\n                    break;\n                } else if (recv_packet1[0] == 0x4d) {\n                    DEBUG_PRINT((\"Get notice packet.\\n\"));\n                    continue;\n                } else {\n                    printf(\"Bad keepalive1 challenge response received.\\n\");\n                    return 1;\n                }\n            }\n        }\n\n        unsigned char keepalive1_seed[4] = {0};\n        int encrypt_type;\n        unsigned char crc[8] = {0};\n        memcpy(keepalive1_seed, &recv_packet1[8], 4);\n        encrypt_type = keepalive1_seed[0] & 3;\n        gen_crc(keepalive1_seed, encrypt_type, crc);\n        keepalive_1_packet2[0] = 0xff;\n        memcpy(keepalive_1_packet2 + 8, keepalive1_seed, 4);\n        memcpy(keepalive_1_packet2 + 12, crc, 8);\n        memcpy(keepalive_1_packet2 + 20, auth_information, 16);\n        keepalive_1_packet2[36] = rand() & 0xff;\n        keepalive_1_packet2[37] = rand() & 0xff;\n\n        sendto(sockfd, keepalive_1_packet2, 38, 0, (struct sockaddr *)&addr, sizeof(addr));\n        if (verbose_flag) {\n            print_packet(\"[Keepalive1_packet2 sent] \", keepalive_1_packet2, 38);\n        }\n        if (logging_flag) {\n            logging(\"[Keepalive1_packet2 sent] \", keepalive_1_packet2, 38);\n        }\n\n        if (recvfrom(sockfd, recv_packet2, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n            get_lasterror(\"Failed to recv data\");\n#else\n            perror(\"Failed to recv data\");\n#endif\n            return 1;\n        } else {\n            if (verbose_flag) {\n                print_packet(\"[Keepalive1 recv] \", recv_packet2, 100);\n            }\n            if (logging_flag) {\n                logging(\"[Keepalive1 recv] \", recv_packet2, 100);\n            }\n\n            if (recv_packet2[0] != 0x07) {\n                printf(\"Bad keepalive1 response received.\\n\");\n                return 1;\n            }\n        }\n\n    } else {\n        unsigned char keepalive_1_packet[42], recv_packet[1024], MD5A[16];\n        memset(keepalive_1_packet, 0, 42);\n        keepalive_1_packet[0] = 0xff;\n        int MD5A_len = 6 + strlen(drcom_config.password);\n        unsigned char MD5A_str[MD5A_len];\n        MD5A_str[0] = 0x03;\n        MD5A_str[1] = 0x01;\n        memcpy(MD5A_str + 2, seed, 4);\n        memcpy(MD5A_str + 6, drcom_config.password, strlen(drcom_config.password));\n        MD5(MD5A_str, MD5A_len, MD5A);\n        memcpy(keepalive_1_packet + 1, MD5A, 16);\n        memcpy(keepalive_1_packet + 20, auth_information, 16);\n        keepalive_1_packet[36] = rand() & 0xff;\n        keepalive_1_packet[37] = rand() & 0xff;\n\n        sendto(sockfd, keepalive_1_packet, 42, 0, (struct sockaddr *)&addr, sizeof(addr));\n\n        if (verbose_flag) {\n            print_packet(\"[Keepalive1 sent] \", keepalive_1_packet, 42);\n        }\n        if (logging_flag) {\n            logging(\"[Keepalive1 sent] \", keepalive_1_packet, 42);\n        }\n\n#ifdef TEST\n        printf(\"[TEST MODE]IN TEST MODE, PASS\\n\");\n        return 0;\n#endif\n\n        socklen_t addrlen = sizeof(addr);\n        while (1) {\n            if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n                get_lasterror(\"Failed to recv data\");\n#else\n                perror(\"Failed to recv data\");\n#endif\n                return 1;\n            } else {\n                if (verbose_flag) {\n                    print_packet(\"[Keepalive1 recv] \", recv_packet, 100);\n                }\n                if (logging_flag) {\n                    logging(\"[Keepalive1 recv] \", recv_packet, 100);\n                }\n\n                if (recv_packet[0] == 0x07) {\n                    break;\n                } else if (recv_packet[0] == 0x4d) {\n                    DEBUG_PRINT((\"Get notice packet.\"));\n                    continue;\n                } else {\n                    printf(\"Bad keepalive1 response received.\\n\");\n                    return 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}\n\nvoid gen_crc(unsigned char seed[], int encrypt_type, unsigned char crc[]) {\n    if (encrypt_type == 0) {\n        char DRCOM_DIAL_EXT_PROTO_CRC_INIT[4] = {0xc7, 0x2f, 0x31, 0x01};\n        char gencrc_tmp[4] = {0x7e};\n        memcpy(crc, DRCOM_DIAL_EXT_PROTO_CRC_INIT, 4);\n        memcpy(crc + 4, gencrc_tmp, 4);\n    } else if (encrypt_type == 1) {\n        unsigned char hash[32] = {0};\n        MD5(seed, 4, hash);\n        crc[0] = hash[2];\n        crc[1] = hash[3];\n        crc[2] = hash[8];\n        crc[3] = hash[9];\n        crc[4] = hash[5];\n        crc[5] = hash[6];\n        crc[6] = hash[13];\n        crc[7] = hash[14];\n    } else if (encrypt_type == 2) {\n        unsigned char hash[32] = {0};\n        MD4(seed, 4, hash);\n        crc[0] = hash[1];\n        crc[1] = hash[2];\n        crc[2] = hash[8];\n        crc[3] = hash[9];\n        crc[4] = hash[4];\n        crc[5] = hash[5];\n        crc[6] = hash[11];\n        crc[7] = hash[12];\n    } else if (encrypt_type == 3) {\n        unsigned char hash[32] = {0};\n        SHA1(seed, 4, hash);\n        crc[0] = hash[2];\n        crc[1] = hash[3];\n        crc[2] = hash[9];\n        crc[3] = hash[10];\n        crc[4] = hash[5];\n        crc[5] = hash[6];\n        crc[6] = hash[15];\n        crc[7] = hash[16];\n    }\n}\n\nvoid keepalive_2_packetbuilder(unsigned char keepalive_2_packet[], int keepalive_counter, int filepacket, int type, int encrypt_type) {\n    keepalive_2_packet[0] = 0x07;\n    keepalive_2_packet[1] = keepalive_counter;\n    keepalive_2_packet[2] = 0x28;\n    keepalive_2_packet[4] = 0x0b;\n    keepalive_2_packet[5] = type;\n    if (filepacket) {\n        keepalive_2_packet[6] = 0x0f;\n        keepalive_2_packet[7] = 0x27;\n    } else {\n        memcpy(keepalive_2_packet + 6, drcom_config.KEEP_ALIVE_VERSION, 2);\n    }\n    keepalive_2_packet[8] = 0x2f;\n    keepalive_2_packet[9] = 0x12;\n    if (type == 3) {\n        unsigned char host_ip[4] = {0};\n        if (strcmp(mode, \"dhcp\") == 0) {\n            sscanf(drcom_config.host_ip, \"%hhd.%hhd.%hhd.%hhd\",\n                   &host_ip[0],\n                   &host_ip[1],\n                   &host_ip[2],\n                   &host_ip[3]);\n            memcpy(keepalive_2_packet + 28, host_ip, 4);\n        } else if (strcmp(mode, \"pppoe\") == 0) {\n            unsigned char crc[8] = {0};\n            gen_crc(keepalive_2_packet, encrypt_type, crc);\n            memcpy(keepalive_2_packet + 32, crc, 8);\n        }\n    }\n}\n\nint keepalive_2(int sockfd, struct sockaddr_in addr, int *keepalive_counter, int *first, int *encrypt_type) {\n    unsigned char keepalive_2_packet[40], recv_packet[1024], tail[4];\n    socklen_t addrlen = sizeof(addr);\n\n#ifdef TEST\n    printf(\"[TEST MODE]IN TEST MODE, PASS\\n\");\n#else\n    if (*first) {\n        // send the file packet\n        memset(keepalive_2_packet, 0, 40);\n        if (strcmp(mode, \"pppoe\") == 0) {\n            keepalive_2_packetbuilder(keepalive_2_packet, *keepalive_counter % 0xFF, *first, 1, *encrypt_type);\n        } else {\n            keepalive_2_packetbuilder(keepalive_2_packet, *keepalive_counter % 0xFF, *first, 1, 0);\n        }\n        (*keepalive_counter)++;\n\n        sendto(sockfd, keepalive_2_packet, 40, 0, (struct sockaddr *)&addr, sizeof(addr));\n\n        if (verbose_flag) {\n            print_packet(\"[Keepalive2_file sent] \", keepalive_2_packet, 40);\n        }\n        if (logging_flag) {\n            logging(\"[Keepalive2_file sent] \", keepalive_2_packet, 40);\n        }\n        if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n            get_lasterror(\"Failed to recv data\");\n#else\n            perror(\"Failed to recv data\");\n#endif\n            return 1;\n        }\n        if (verbose_flag) {\n            print_packet(\"[Keepalive2_file recv] \", recv_packet, 40);\n        }\n        if (logging_flag) {\n            logging(\"[Keepalive2_file recv] \", recv_packet, 40);\n        }\n\n        if (recv_packet[0] == 0x07) {\n            if (recv_packet[2] == 0x10) {\n                if (verbose_flag) {\n                    printf(\"Filepacket received.\\n\");\n                }\n            } else if (recv_packet[2] != 0x28) {\n                if (verbose_flag) {\n                    printf(\"Bad keepalive2 response received.\\n\");\n                }\n                return 1;\n            }\n        } else {\n            printf(\"Bad keepalive2 response received.\\n\");\n            return 1;\n        }\n    }\n#endif\n\n    // send the first packet\n    *first = 0;\n    memset(keepalive_2_packet, 0, 40);\n    if (strcmp(mode, \"pppoe\") == 0) {\n        keepalive_2_packetbuilder(keepalive_2_packet, *keepalive_counter % 0xFF, *first, 1, *encrypt_type);\n    } else {\n        keepalive_2_packetbuilder(keepalive_2_packet, *keepalive_counter % 0xFF, *first, 1, 0);\n    }\n    (*keepalive_counter)++;\n    sendto(sockfd, keepalive_2_packet, 40, 0, (struct sockaddr *)&addr, sizeof(addr));\n\n    if (verbose_flag) {\n        print_packet(\"[Keepalive2_A sent] \", keepalive_2_packet, 40);\n    }\n    if (logging_flag) {\n        logging(\"[Keepalive2_A sent] \", keepalive_2_packet, 40);\n    }\n\n#ifdef TEST\n    unsigned char test[4] = {0x13, 0x38, 0xe2, 0x11};\n    memcpy(tail, test, 4);\n    print_packet(\"[TEST MODE]<PREP TAIL> \", tail, 4);\n#else\n    if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to recv data\");\n#else\n        perror(\"Failed to recv data\");\n#endif\n        return 1;\n    }\n    if (verbose_flag) {\n        print_packet(\"[Keepalive2_B recv] \", recv_packet, 40);\n    }\n    if (logging_flag) {\n        logging(\"[Keepalive2_B recv] \", recv_packet, 40);\n    }\n\n    if (recv_packet[0] == 0x07) {\n        if (recv_packet[2] != 0x28) {\n            printf(\"Bad keepalive2 response received.\\n\");\n            return 1;\n        }\n    } else {\n        printf(\"Bad keepalive2 response received.\\n\");\n        return 1;\n    }\n    memcpy(tail, &recv_packet[16], 4);\n#endif\n\n#ifdef DEBUG\n    print_packet(\"<GET TAIL> \", tail, 4);\n#endif\n\n    // send the third packet\n    memset(keepalive_2_packet, 0, 40);\n    if (strcmp(mode, \"pppoe\") == 0) {\n        keepalive_2_packetbuilder(keepalive_2_packet, *keepalive_counter % 0xFF, *first, 3, *encrypt_type);\n    } else {\n        keepalive_2_packetbuilder(keepalive_2_packet, *keepalive_counter % 0xFF, *first, 3, 0);\n    }\n    memcpy(keepalive_2_packet + 16, tail, 4);\n    (*keepalive_counter)++;\n    sendto(sockfd, keepalive_2_packet, 40, 0, (struct sockaddr *)&addr, sizeof(addr));\n\n    if (verbose_flag) {\n        print_packet(\"[Keepalive2_C sent] \", keepalive_2_packet, 40);\n    }\n    if (logging_flag) {\n        logging(\"[Keepalive2_C sent] \", keepalive_2_packet, 40);\n    }\n\n#ifdef TEST\n    printf(\"[TEST MODE]IN TEST MODE, PASS\\n\");\n    exit(0);\n#endif\n\n    if (recvfrom(sockfd, recv_packet, 1024, 0, (struct sockaddr *)&addr, &addrlen) < 0) {\n#ifdef WIN32\n        get_lasterror(\"Failed to recv data\");\n#else\n        perror(\"Failed to recv data\");\n#endif\n        return 1;\n    }\n    if (verbose_flag) {\n        print_packet(\"[Keepalive2_D recv] \", recv_packet, 40);\n    }\n    if (logging_flag) {\n        logging(\"[Keepalive2_D recv] \", recv_packet, 40);\n    }\n\n    if (recv_packet[0] == 0x07) {\n        if (recv_packet[2] != 0x28) {\n            printf(\"Bad keepalive2 response received.\\n\");\n            return 1;\n        }\n    } else {\n        printf(\"Bad keepalive2 response received.\\n\");\n        return 1;\n    }\n\n    return 0;\n}"
  },
  {
    "path": "keepalive.h",
    "content": "#ifndef KEEPALIVE_H_\n#define KEEPALIVE_H_\n\nint keepalive_1(int sockfd, struct sockaddr_in addr, unsigned char seed[], unsigned char auth_information[]);\nint keepalive_2(int sockfd, struct sockaddr_in addr, int *keepalive_counter, int *first, int *encrypt_type);\nvoid gen_crc(unsigned char seed[], int encrypt_type, unsigned char crc[]);\nvoid keepalive_2_packetbuilder(unsigned char keepalive_2_packet[], int keepalive_counter, int filepacket, int type, int encrypt_type);\n\n#endif  // KEEPALIVE_H_"
  },
  {
    "path": "libs/common.c",
    "content": "#ifdef linux\n\n/*\n * 一些通用的代码\n */\n#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\n#include <ctype.h>\n#include <errno.h>\n#include <time.h>\n#include \"common.h\"\n\n// #ifdef LINUX\n#include <unistd.h>\n#include <arpa/inet.h>\n#include <net/ethernet.h>\n#include <sys/select.h>\n#include <net/if_arp.h>\n#include <net/if.h>\n#include <sys/ioctl.h>\n#include <netpacket/packet.h>\n#define PATH_SEP   '/'\n// #elif WIN32\n// # include <windows.h>\n// # include <pcap.h>\n// # define PATH_SEP   '\\\\'\n// #endif\n\n\nextern int getexedir(char *exedir)\n{\n// #ifdef LINUX\n    int cnt = readlink(\"/proc/self/exe\", exedir, EXE_PATH_MAX);\n// #elif WIN32\n//     int cnt = GetModuleFileName(NULL, exedir, EXE_PATH_MAX);\n// #endif\n    if (cnt < 0 || cnt >= EXE_PATH_MAX)\n        return -1;\n    _D(\"exedir: %s\\n\", exedir);\n    char *end = strrchr(exedir, PATH_SEP);\n    if (!end) return -1;\n    *(end+1) = '\\0';\n    _D(\"exedir: %s\\n\", exedir);\n    return 0;\n}\n\nextern int mac_equal(uchar const *mac1, uchar const *mac2)\n{\n\tint i;\n\tfor (i = 0; i < ETH_ALEN; ++i) {\n\t\tif (mac1[i] != mac2[i])\n\t\t\treturn 0;\n\t}\n\n\treturn 1;\n}\nextern int ip_equal(int type, void const *ip1, void const *ip2)\n{\n\tuchar const *p1 = (uchar const*)ip1;\n\tuchar const *p2 = (uchar const*)ip2;\n\tint len = 4;\n\tif (AF_INET6 == type) {\n\t\tlen = 16;\n\t}\n\tint i;\n\tfor (i = 0; i < len; ++i) {\n\t\tif (p1[i] != p2[i])\n\t\t\treturn 0;\n\t}\n\treturn 1;\n}\n\nstatic int is_filter(char const *ifname)\n{\n\t/* 过滤掉无线，虚拟机接口等 */\n\tchar const *filter[] = {\n\t\t/* windows */\n\t\t\"Wireless\", \"Microsoft\",\n\t\t\"Virtual\",\n\t\t/* linux */\n\t\t\"lo\", \"wlan\", \"vboxnet\",\n\t\t\"ifb\", \"gre\", \"teql\",\n\t\t\"br\", \"imq\", \"ra\",\n\t\t\"wds\", \"sit\", \"apcli\",\n\t};\n\tunsigned int i;\n\tfor (i = 0; i < ARRAY_SIZE(filter); ++i) {\n\t\tif (strstr(ifname, filter[i]))\n\t\t\treturn 1;\n\t}\n\treturn 0;\n}\n// #ifdef LINUX\nstatic char *get_ifname_from_buff(char *buff)\n{\n\tchar *s;\n\twhile (isspace(*buff))\n\t\t++buff;\n\ts = buff;\n\twhile (':' != *buff && '\\0' != *buff)\n\t\t++buff;\n\t*buff = '\\0';\n\treturn s;\n}\n// #endif\n/*\n * 获取所有网络接口\n * ifnames 实际获取的接口\n * cnt     两个作用，1：传入表示ifnames最多可以存储的接口个数\n *                   2：返回表示实际获取了的接口个数\n * 返回接口个数在cnt里\n * @return: >=0  成功，实际获取的接口个数\n *          -1 获取失败\n *          -2 cnt过小\n */\nextern int getall_ifs(iflist_t *ifs, int *cnt)\n{\n\tint i = 0;\n\tif (!ifs || *cnt <= 0) return -2;\n\n// #ifdef LINUX    /* linux (unix osx?) */\n#define _PATH_PROCNET_DEV \"/proc/net/dev\"\n#define BUFF_LINE_MAX\t(1024)\n\tchar buff[BUFF_LINE_MAX];\n\tFILE *fd = fopen(_PATH_PROCNET_DEV, \"r\");\n\tchar *name;\n\tif (NULL == fd) {\n\t\tperror(\"fopen\");\n\t\treturn -1;\n\t}\n\t/* _PATH_PROCNET_DEV文件格式如下,...表示后面我们不关心\n\t * Inter-|   Receive ...\n\t * face |bytes    packets ...\n\t * eth0: 147125283  119599 ...\n\t * wlan0:  229230    2635   ...\n\t * lo: 10285509   38254  ...\n\t */\n\t/* 略过开始两行 */\n\tfgets(buff, BUFF_LINE_MAX, fd);\n\tfgets(buff, BUFF_LINE_MAX, fd);\n\twhile (NULL != fgets(buff, BUFF_LINE_MAX, fd)) {\n\t\tname = get_ifname_from_buff(buff);\n\t\t_D(\"%s\\n\", name);\n\t\t/* 过滤无关网络接口 */\n\t\tif (is_filter(name)) {\n\t\t\t_D(\"filtered %s.\\n\", name);\n\t\t\tcontinue;\n\t\t}\n\t\tstrncpy(ifs[i].name, name, IFNAMSIZ);\n\t\t_D(\"ifs[%d].name: %s\\n\", i, ifs[i].name);\n\t\t++i;\n\t\tif (i >= *cnt) {\n\t\t\tfclose(fd);\n\t\t\treturn -2;\n\t\t}\n\t}\n\tfclose(fd);\n\n// #elif WIN32\n// \tpcap_if_t *alldevs;\n// \tchar errbuf[PCAP_ERRBUF_SIZE];\n// \tif (-1 == pcap_findalldevs(&alldevs, errbuf)) {\n// \t\t_M(\"Get interfaces handler error: %s\\n\", errbuf);\n// \t\treturn -1;\n// \t}\n// \tfor (pcap_if_t *d = alldevs; d; d = d->next) {\n// \t\tif (is_filter(d->description)) {\n// \t\t\t_D(\"filtered %s.\\n\", d->description);\n// \t\t\tcontinue;\n// \t\t}\n// \t\tif (i >= *cnt) return -2;\n// \t\tstrncpy(ifs[i].name, d->name, IFNAMSIZ);\n// \t\tstrncpy(ifs[i].desc, d->description, IFDESCSIZ);\n// \t\t++i;\n// \t}\n// \tpcap_freealldevs(alldevs);\n// #endif\n\n\t*cnt = i;\n\treturn i;\n}\n\nextern char const *format_time(void)\n{\n\tstatic char buff[FORMAT_TIME_MAX];\n\ttime_t rawtime;\n\tstruct tm *timeinfo;\n\n\ttime(&rawtime);\n\ttimeinfo = localtime(&rawtime);\n\tif (NULL == timeinfo) return NULL;\n\tstrftime(buff, sizeof(buff), \"%Y-%m-%d %H:%M:%S\", timeinfo);\n\n\treturn buff;\n}\nextern int copy(char const *f1, char const *f2)\n{\n\tif (NULL == f1 || NULL == f2) return -1;\n\tFILE *src, *dst;\n\tsrc = fopen(f1, \"r\");\n\tdst = fopen(f2, \"w\");\n\tif (NULL == src || NULL == dst) return -1;\n\tchar buff[1024];\n\tint n;\n\twhile (0 < (n = fread(buff, 1, 1024, src)))\n\t\tfwrite(buff, 1, n, dst);\n\n\tfclose(src);\n\tfclose(dst);\n\n\treturn 0;\n}\n/*\n * 本地是否是小端序\n * @return: !0: 是\n *           0: 不是(大端序)\n */\nstatic int islsb()\n{\n\tstatic uint16 a = 0x0001;\n\treturn (int)(*(uchar*)&a);\n}\nstatic uint16 exorders(uint16 n)\n{\n\treturn ((n>>8)|(n<<8));\n}\nstatic uint32 exorderl(uint32 n)\n{\n\treturn (n>>24)|((n&0x00ff0000)>>8)|((n&0x0000ff00)<<8)|(n<<24);\n}\nextern uint16 htols(uint16 n)\n{\n\treturn islsb()?n:exorders(n);\n}\nextern uint16 htoms(uint16 n)\n{\n\treturn islsb()?exorders(n):n;\n}\nextern uint16 ltohs(uint16 n)\n{\n\treturn islsb()?n:exorders(n);\n}\nextern uint16 mtohs(uint16 n)\n{\n\treturn islsb()?exorders(n):n;\n}\nextern uint32 htoll(uint32 n)\n{\n\treturn islsb()?n:exorderl(n);\n}\nextern uint32 htoml(uint32 n)\n{\n\treturn islsb()?exorderl(n):n;\n}\nextern uint32 ltohl(uint32 n)\n{\n\treturn islsb()?n:exorderl(n);\n}\nextern uint32 mtohl(uint32 n)\n{\n\treturn islsb()?exorderl(n):n;\n}\nextern uchar const *format_mac(uchar const *macarr)\n{\n\tstatic uchar formatmac[] =\n\t\t\"xx:xx:xx:xx:xx:xx\";\n\tif (NULL == macarr)\n\t\treturn NULL;\n\tsprintf((char*)formatmac, \"%.2X:%.2X:%.2X:%.2X:%.2X:%.2X\",\n\t\t\tmacarr[0], macarr[1], macarr[2],\n\t\t\tmacarr[3], macarr[4], macarr[5]);\n\treturn formatmac;\n}\n/*\n * 以16进制打印数据\n */\nextern void format_data(uchar const *d, size_t len)\n{\n\tint i;\n\tfor (i = 0; i < (long)len; ++i) {\n\t\tif (i != 0 && i%16 == 0)\n\t\t\t_M(\"\\n\");\n\t\t_M(\"%02x \", d[i]);\n\t}\n\t_M(\"\\n\");\n}\n\n#ifdef LINUX\n/*\n * 返回t1-t0的时间差\n * 由于这里精度没必要达到ns，故返回相差微秒ms\n * @return: 时间差，单位微秒(1s == 1000ms)\n */\nextern long difftimespec(struct timespec t1, struct timespec t0)\n{\n\tlong d = t1.tv_sec-t0.tv_sec;\n\td *= 1000;\n\td += (t1.tv_nsec-t0.tv_nsec)/(long)(1e6);\n\treturn d;\n}\n\n/*\n * 判断网络是否连通\n * 最长延时3s，也就是说如果3s内没有检测到数据回应，那么认为网络不通\n * TODO 使用icmp协议判断\n * @return: !0: 连通\n *           0: 没有连通\n */\nextern int isnetok(char const *ifname)\n{\n\tstatic char baidu[] = \"baidu.com\";\n\tsleep(100);\n\treturn 1;\n}\n\n/*\n * 休眠ms微秒\n */\nextern void msleep(long ms)\n{\n\tstruct timeval tv;\n\ttv.tv_sec = ms/1000;\n\ttv.tv_usec = ms%1000*1000;\n\tselect(0, 0, 0, 0, &tv);\n}\n#endif /* LINUX */\n\n#endif"
  },
  {
    "path": "libs/common.h",
    "content": "#ifndef COMMON_H__\n#define COMMON_H__\n/*\n * 通用的代码和定义\n */\ntypedef unsigned char uchar;\t/* 一个字节 */\ntypedef unsigned short uint16;\t/* 两个字节 */\ntypedef unsigned int uint32;\t/* 四个字节 */\n\n/* 用户名和密码长度 */\n#define UNAME_LEN\t(32)\n#define PWD_LEN\t\t(32)\n\n#define FORMAT_TIME_MAX\t(64)\n\n// #ifdef LINUX\n#include <linux/limits.h>\n#include <netinet/if_ether.h>\n#include <arpa/inet.h>\n#include <net/if.h>\n#define EXE_PATH_MAX   (PATH_MAX+1)\n// #elif WIN32\n// # include <windows.h>\n// # define ETH_ALEN\t    (6)\n// # define IF_NAMSIZE\t    (64)\n// # define MTU_MAX\t    (65536)\n// # define EXE_PATH_MAX   (MAX_PATH+1)\n// # define IFDESCSIZ      (126)\n// #endif\n\ntypedef struct {\n    char name[IF_NAMESIZE]; /* linux下是eth0, windows采用的是注册表类似的(\\Device\\NPF_{xxxx-xxx-xx-xx-xxx}) */\n// #ifdef WIN32\n//     char desc[IFDESCSIZ]; /* windows下描述(AMD PCNET Family PCI Ethernet Adapter) */\n// #endif\n}iflist_t;\n\n\n#undef ARRAY_SIZE\n#define ARRAY_SIZE(arr)\t(sizeof(arr)/sizeof(arr[0]))\n\n#define MAX(x, y)\t((x)>(y)?(x):(y))\n#define MIN(x, y)\t((x)>(y)?(y):(x))\n\n#undef PRINT\n#ifdef GUI\n# include <glib.h>\n# define PRINT(...) g_print(__VA_ARGS__)\n#else\n# include <stdio.h>\n# define PRINT(...) fprintf(stderr, __VA_ARGS__)\n#endif\n\n#ifdef DEBUG\n# define _D(...) \\\n    do { \\\n        PRINT(\"%s:%s:%d:\", format_time(), __FILE__, __LINE__); \\\n        PRINT(__VA_ARGS__); \\\n    } while(0)\n#else\n# define _D(...)    ((void)0)\n#endif\n\n#define _M(...)    PRINT(__VA_ARGS__);\n\n/*\n * 获取程序所在的实际绝对路径的目录\n * exedir: 返回目录，加上\\0一起长度是EXE_PATH_MAX，\n *         如果本上长度达到了EXE_PATH_MAX(不包括\\0)，那么也会返回失败\n * @return: 0: 成功\n *         !0: 失败\n */\nextern int getexedir(char *exedir);\n/*\n * 比较两个mac是否相同\n * @return: 0: 不同\n *         !0: 相同\n */\nextern int mac_equal(uchar const *mac1, uchar const *mac2);\n\n/*\n * 判断两个ip是否相等\n * type: AF_INET or AF_INET6, 分别对应ipv4,ipv6\n * ip1, ip2: 比较的两个ip，同为struct in_addr或struct in6_addr的指针\n * @return: 0: 不同\n *         !0: 相同\n */\nextern int ip_equal(int type, void const *ip1, void const *ip2);\n\n/*\n * 获取所有网络接口\n * ifnames 实际获取的接口\n * cnt     两个作用，1：传入表示ifnames最多可以存储的接口个数\n *                   2：返回表示实际获取了的接口个数\n * 返回接口个数在cnt里\n * @return: >=0  成功，实际获取的接口个数\n *          -1 获取失败\n *          -2 cnt过小\n */\nextern int getall_ifs(iflist_t *ifs, int *cnt);\n/*\n * 获取当前时间按照\n * yyyy-MM-dd HH:mm:ss\n * 格式返回\n * NOTE 不要去修改返回结果，并且不是线程安全的\n * @return: NULL: 失败\n *         !NULL: 存储的结果\n */\nextern char const *format_time(void);\n/*\n * 简单的复制文件，暂时不进行细致错误检查\n * NOTE 是绝对路径\n * scr: 源文件\n * dst: 目标文件\n * @return: 0: 成功\n *         -1: 失败\n */\nextern int copy(char const *src, char const *dst);\n\n/*\n * 字节序转换相关函数\n * host to lsb/msb short/long (host->l/m)\n * lsb/msb to host short/long (l/m->host)\n */\nextern uint16 htols(uint16 n);\nextern uint16 htoms(uint16 n);\nextern uint16 ltohs(uint16 n);\nextern uint16 mtohs(uint16 n);\n\nextern uint32 htoll(uint32 n);\nextern uint32 htoml(uint32 n);\nextern uint32 ltohl(uint32 n);\nextern uint32 mtohl(uint32 n);\n\nextern uchar const *format_mac(uchar const *mac);\n\n/*\n * 判断网络是否连通\n * ifname: 接口名字\n * @return: !0: 连通\n *           0: 没有连通\n */\nextern int isnetok(char const *ifname);\n/*\n * 返回t1-t0的时间差\n * 由于这里精度没必要达到ns，故返回相差微秒ms\n * @return: 时间差，单位微秒(1s == 1000ms)\n */\nextern long difftimespec(struct timespec t1, struct timespec t0);\n\n/*\n * 休眠ms微秒\n */\nextern void msleep(long ms);\n\n/*\n * 以16进制打印数据\n */\nextern void format_data(uchar const *d, size_t len);\n\n#endif"
  },
  {
    "path": "libs/md4.c",
    "content": "/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD4 Message-Digest Algorithm (RFC 1320).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * (This is a heavily cut-down \"BSD license\".)\n *\n * This differs from Colin Plumb's older public domain implementation in that\n * no exactly 32-bit integer data type is required (any 32-bit or wider\n * unsigned integer data type will do), there's no compile-time endianness\n * configuration, and the function prototypes match OpenSSL's.  No code from\n * Colin Plumb's implementation has been reused; this comment merely compares\n * the properties of the two independent implementations.\n *\n * The primary goals of this implementation are portability and ease of use.\n * It is meant to be fast, but not as fast as possible.  Some known\n * optimizations are not included to reduce source code size and avoid\n * compile-time configuration.\n */\n\n#ifndef HAVE_OPENSSL\n\n#include <string.h>\n\n#include \"md4.h\"\n\n/*\n * The basic MD4 functions.\n *\n * F and G are optimized compared to their RFC 1320 definitions, with the\n * optimization for F borrowed from Colin Plumb's MD5 implementation.\n */\n#define F(x, y, z)\t\t\t((z) ^ ((x) & ((y) ^ (z))))\n#define G(x, y, z)\t\t\t(((x) & ((y) | (z))) | ((y) & (z)))\n#define H(x, y, z)\t\t\t((x) ^ (y) ^ (z))\n\n/*\n * The MD4 transformation for all three rounds.\n */\n#define STEP(f, a, b, c, d, x, s) \\\n\t(a) += f((b), (c), (d)) + (x); \\\n\t(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));\n\n/*\n * SET reads 4 input bytes in little-endian byte order and stores them in a\n * properly aligned word in host byte order.\n *\n * The check for little-endian architectures that tolerate unaligned memory\n * accesses is just an optimization.  Nothing will break if it fails to detect\n * a suitable architecture.\n *\n * Unfortunately, this optimization may be a C strict aliasing rules violation\n * if the caller's data buffer has effective type that cannot be aliased by\n * MD4_u32plus.  In practice, this problem may occur if these MD4 routines are\n * inlined into a calling function, or with future and dangerously advanced\n * link-time optimizations.  For the time being, keeping these MD4 routines in\n * their own translation unit avoids the problem.\n */\n#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)\n#define SET(n) \\\n\t(*(MD4_u32plus *)&ptr[(n) * 4])\n#define GET(n) \\\n\tSET(n)\n#else\n#define SET(n) \\\n\t(ctx->block[(n)] = \\\n\t(MD4_u32plus)ptr[(n) * 4] | \\\n\t((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \\\n\t((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \\\n\t((MD4_u32plus)ptr[(n) * 4 + 3] << 24))\n#define GET(n) \\\n\t(ctx->block[(n)])\n#endif\n\n/*\n * This processes one or more 64-byte data blocks, but does NOT update the bit\n * counters.  There are no alignment requirements.\n */\nstatic const void *body(MD4_CTX *ctx, const void *data, unsigned long size)\n{\n\tconst unsigned char *ptr;\n\tMD4_u32plus a, b, c, d;\n\tMD4_u32plus saved_a, saved_b, saved_c, saved_d;\n\tconst MD4_u32plus ac1 = 0x5a827999, ac2 = 0x6ed9eba1;\n\n\tptr = (const unsigned char *)data;\n\n\ta = ctx->a;\n\tb = ctx->b;\n\tc = ctx->c;\n\td = ctx->d;\n\n\tdo {\n\t\tsaved_a = a;\n\t\tsaved_b = b;\n\t\tsaved_c = c;\n\t\tsaved_d = d;\n\n/* Round 1 */\n\t\tSTEP(F, a, b, c, d, SET(0), 3)\n\t\tSTEP(F, d, a, b, c, SET(1), 7)\n\t\tSTEP(F, c, d, a, b, SET(2), 11)\n\t\tSTEP(F, b, c, d, a, SET(3), 19)\n\t\tSTEP(F, a, b, c, d, SET(4), 3)\n\t\tSTEP(F, d, a, b, c, SET(5), 7)\n\t\tSTEP(F, c, d, a, b, SET(6), 11)\n\t\tSTEP(F, b, c, d, a, SET(7), 19)\n\t\tSTEP(F, a, b, c, d, SET(8), 3)\n\t\tSTEP(F, d, a, b, c, SET(9), 7)\n\t\tSTEP(F, c, d, a, b, SET(10), 11)\n\t\tSTEP(F, b, c, d, a, SET(11), 19)\n\t\tSTEP(F, a, b, c, d, SET(12), 3)\n\t\tSTEP(F, d, a, b, c, SET(13), 7)\n\t\tSTEP(F, c, d, a, b, SET(14), 11)\n\t\tSTEP(F, b, c, d, a, SET(15), 19)\n\n/* Round 2 */\n\t\tSTEP(G, a, b, c, d, GET(0) + ac1, 3)\n\t\tSTEP(G, d, a, b, c, GET(4) + ac1, 5)\n\t\tSTEP(G, c, d, a, b, GET(8) + ac1, 9)\n\t\tSTEP(G, b, c, d, a, GET(12) + ac1, 13)\n\t\tSTEP(G, a, b, c, d, GET(1) + ac1, 3)\n\t\tSTEP(G, d, a, b, c, GET(5) + ac1, 5)\n\t\tSTEP(G, c, d, a, b, GET(9) + ac1, 9)\n\t\tSTEP(G, b, c, d, a, GET(13) + ac1, 13)\n\t\tSTEP(G, a, b, c, d, GET(2) + ac1, 3)\n\t\tSTEP(G, d, a, b, c, GET(6) + ac1, 5)\n\t\tSTEP(G, c, d, a, b, GET(10) + ac1, 9)\n\t\tSTEP(G, b, c, d, a, GET(14) + ac1, 13)\n\t\tSTEP(G, a, b, c, d, GET(3) + ac1, 3)\n\t\tSTEP(G, d, a, b, c, GET(7) + ac1, 5)\n\t\tSTEP(G, c, d, a, b, GET(11) + ac1, 9)\n\t\tSTEP(G, b, c, d, a, GET(15) + ac1, 13)\n\n/* Round 3 */\n\t\tSTEP(H, a, b, c, d, GET(0) + ac2, 3)\n\t\tSTEP(H, d, a, b, c, GET(8) + ac2, 9)\n\t\tSTEP(H, c, d, a, b, GET(4) + ac2, 11)\n\t\tSTEP(H, b, c, d, a, GET(12) + ac2, 15)\n\t\tSTEP(H, a, b, c, d, GET(2) + ac2, 3)\n\t\tSTEP(H, d, a, b, c, GET(10) + ac2, 9)\n\t\tSTEP(H, c, d, a, b, GET(6) + ac2, 11)\n\t\tSTEP(H, b, c, d, a, GET(14) + ac2, 15)\n\t\tSTEP(H, a, b, c, d, GET(1) + ac2, 3)\n\t\tSTEP(H, d, a, b, c, GET(9) + ac2, 9)\n\t\tSTEP(H, c, d, a, b, GET(5) + ac2, 11)\n\t\tSTEP(H, b, c, d, a, GET(13) + ac2, 15)\n\t\tSTEP(H, a, b, c, d, GET(3) + ac2, 3)\n\t\tSTEP(H, d, a, b, c, GET(11) + ac2, 9)\n\t\tSTEP(H, c, d, a, b, GET(7) + ac2, 11)\n\t\tSTEP(H, b, c, d, a, GET(15) + ac2, 15)\n\n\t\ta += saved_a;\n\t\tb += saved_b;\n\t\tc += saved_c;\n\t\td += saved_d;\n\n\t\tptr += 64;\n\t} while (size -= 64);\n\n\tctx->a = a;\n\tctx->b = b;\n\tctx->c = c;\n\tctx->d = d;\n\n\treturn ptr;\n}\n\nvoid MD4_Init(MD4_CTX *ctx)\n{\n\tctx->a = 0x67452301;\n\tctx->b = 0xefcdab89;\n\tctx->c = 0x98badcfe;\n\tctx->d = 0x10325476;\n\n\tctx->lo = 0;\n\tctx->hi = 0;\n}\n\nvoid MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)\n{\n\tMD4_u32plus saved_lo;\n\tunsigned long used, available;\n\n\tsaved_lo = ctx->lo;\n\tif ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)\n\t\tctx->hi++;\n\tctx->hi += size >> 29;\n\n\tused = saved_lo & 0x3f;\n\n\tif (used) {\n\t\tavailable = 64 - used;\n\n\t\tif (size < available) {\n\t\t\tmemcpy(&ctx->buffer[used], data, size);\n\t\t\treturn;\n\t\t}\n\n\t\tmemcpy(&ctx->buffer[used], data, available);\n\t\tdata = (const unsigned char *)data + available;\n\t\tsize -= available;\n\t\tbody(ctx, ctx->buffer, 64);\n\t}\n\n\tif (size >= 64) {\n\t\tdata = body(ctx, data, size & ~(unsigned long)0x3f);\n\t\tsize &= 0x3f;\n\t}\n\n\tmemcpy(ctx->buffer, data, size);\n}\n\n#define OUT(dst, src) \\\n\t(dst)[0] = (unsigned char)(src); \\\n\t(dst)[1] = (unsigned char)((src) >> 8); \\\n\t(dst)[2] = (unsigned char)((src) >> 16); \\\n\t(dst)[3] = (unsigned char)((src) >> 24);\n\nvoid MD4_Final(unsigned char *result, MD4_CTX *ctx)\n{\n\tunsigned long used, available;\n\n\tused = ctx->lo & 0x3f;\n\n\tctx->buffer[used++] = 0x80;\n\n\tavailable = 64 - used;\n\n\tif (available < 8) {\n\t\tmemset(&ctx->buffer[used], 0, available);\n\t\tbody(ctx, ctx->buffer, 64);\n\t\tused = 0;\n\t\tavailable = 64;\n\t}\n\n\tmemset(&ctx->buffer[used], 0, available - 8);\n\n\tctx->lo <<= 3;\n\tOUT(&ctx->buffer[56], ctx->lo)\n\tOUT(&ctx->buffer[60], ctx->hi)\n\n\tbody(ctx, ctx->buffer, 64);\n\n\tOUT(&result[0], ctx->a)\n\tOUT(&result[4], ctx->b)\n\tOUT(&result[8], ctx->c)\n\tOUT(&result[12], ctx->d)\n\n\tmemset(ctx, 0, sizeof(*ctx));\n}\n\nvoid MD4(const void *data, unsigned long size, unsigned char *result) {\n\tMD4_CTX ctx;\n\tMD4_Init(&ctx);\n\tMD4_Update(&ctx, data, size);\n\tMD4_Final(result, &ctx);\n}\n\n#endif\n"
  },
  {
    "path": "libs/md4.h",
    "content": "/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD4 Message-Digest Algorithm (RFC 1320).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * See md4.c for more information.\n */\n\n#ifdef HAVE_OPENSSL\n#include <openssl/md4.h>\n#elif !defined(_MD4_H)\n#define _MD4_H\n\n/* Any 32-bit or wider unsigned integer data type will do */\ntypedef unsigned int MD4_u32plus;\n\ntypedef struct {\n\tMD4_u32plus lo, hi;\n\tMD4_u32plus a, b, c, d;\n\tunsigned char buffer[64];\n\tMD4_u32plus block[16];\n} MD4_CTX;\n\nextern void MD4_Init(MD4_CTX *ctx);\nextern void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size);\nextern void MD4_Final(unsigned char *result, MD4_CTX *ctx);\n\nvoid MD4(const void *data, unsigned long size, unsigned char *result);\n\n#endif\n"
  },
  {
    "path": "libs/md5.c",
    "content": "/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD5 Message-Digest Algorithm (RFC 1321).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * (This is a heavily cut-down \"BSD license\".)\n *\n * This differs from Colin Plumb's older public domain implementation in that\n * no exactly 32-bit integer data type is required (any 32-bit or wider\n * unsigned integer data type will do), there's no compile-time endianness\n * configuration, and the function prototypes match OpenSSL's.  No code from\n * Colin Plumb's implementation has been reused; this comment merely compares\n * the properties of the two independent implementations.\n *\n * The primary goals of this implementation are portability and ease of use.\n * It is meant to be fast, but not as fast as possible.  Some known\n * optimizations are not included to reduce source code size and avoid\n * compile-time configuration.\n */\n\n#ifndef HAVE_OPENSSL\n\n#include <string.h>\n\n#include \"md5.h\"\n\n/*\n * The basic MD5 functions.\n *\n * F and G are optimized compared to their RFC 1321 definitions for\n * architectures that lack an AND-NOT instruction, just like in Colin Plumb's\n * implementation.\n */\n#define F(x, y, z)\t\t\t((z) ^ ((x) & ((y) ^ (z))))\n#define G(x, y, z)\t\t\t((y) ^ ((z) & ((x) ^ (y))))\n#define H(x, y, z)\t\t\t(((x) ^ (y)) ^ (z))\n#define H2(x, y, z)\t\t\t((x) ^ ((y) ^ (z)))\n#define I(x, y, z)\t\t\t((y) ^ ((x) | ~(z)))\n\n/*\n * The MD5 transformation for all four rounds.\n */\n#define STEP(f, a, b, c, d, x, t, s) \\\n\t(a) += f((b), (c), (d)) + (x) + (t); \\\n\t(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \\\n\t(a) += (b);\n\n/*\n * SET reads 4 input bytes in little-endian byte order and stores them in a\n * properly aligned word in host byte order.\n *\n * The check for little-endian architectures that tolerate unaligned memory\n * accesses is just an optimization.  Nothing will break if it fails to detect\n * a suitable architecture.\n *\n * Unfortunately, this optimization may be a C strict aliasing rules violation\n * if the caller's data buffer has effective type that cannot be aliased by\n * MD5_u32plus.  In practice, this problem may occur if these MD5 routines are\n * inlined into a calling function, or with future and dangerously advanced\n * link-time optimizations.  For the time being, keeping these MD5 routines in\n * their own translation unit avoids the problem.\n */\n#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)\n#define SET(n) \\\n\t(*(MD5_u32plus *)&ptr[(n) * 4])\n#define GET(n) \\\n\tSET(n)\n#else\n#define SET(n) \\\n\t(ctx->block[(n)] = \\\n\t(MD5_u32plus)ptr[(n) * 4] | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \\\n\t((MD5_u32plus)ptr[(n) * 4 + 3] << 24))\n#define GET(n) \\\n\t(ctx->block[(n)])\n#endif\n\n/*\n * This processes one or more 64-byte data blocks, but does NOT update the bit\n * counters.  There are no alignment requirements.\n */\nstatic const void *body(MD5_CTX *ctx, const void *data, unsigned long size)\n{\n\tconst unsigned char *ptr;\n\tMD5_u32plus a, b, c, d;\n\tMD5_u32plus saved_a, saved_b, saved_c, saved_d;\n\n\tptr = (const unsigned char *)data;\n\n\ta = ctx->a;\n\tb = ctx->b;\n\tc = ctx->c;\n\td = ctx->d;\n\n\tdo {\n\t\tsaved_a = a;\n\t\tsaved_b = b;\n\t\tsaved_c = c;\n\t\tsaved_d = d;\n\n/* Round 1 */\n\t\tSTEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)\n\t\tSTEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)\n\t\tSTEP(F, c, d, a, b, SET(2), 0x242070db, 17)\n\t\tSTEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)\n\t\tSTEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)\n\t\tSTEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)\n\t\tSTEP(F, c, d, a, b, SET(6), 0xa8304613, 17)\n\t\tSTEP(F, b, c, d, a, SET(7), 0xfd469501, 22)\n\t\tSTEP(F, a, b, c, d, SET(8), 0x698098d8, 7)\n\t\tSTEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)\n\t\tSTEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)\n\t\tSTEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)\n\t\tSTEP(F, a, b, c, d, SET(12), 0x6b901122, 7)\n\t\tSTEP(F, d, a, b, c, SET(13), 0xfd987193, 12)\n\t\tSTEP(F, c, d, a, b, SET(14), 0xa679438e, 17)\n\t\tSTEP(F, b, c, d, a, SET(15), 0x49b40821, 22)\n\n/* Round 2 */\n\t\tSTEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)\n\t\tSTEP(G, d, a, b, c, GET(6), 0xc040b340, 9)\n\t\tSTEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)\n\t\tSTEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)\n\t\tSTEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)\n\t\tSTEP(G, d, a, b, c, GET(10), 0x02441453, 9)\n\t\tSTEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)\n\t\tSTEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)\n\t\tSTEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)\n\t\tSTEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)\n\t\tSTEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)\n\t\tSTEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)\n\t\tSTEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)\n\t\tSTEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)\n\t\tSTEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)\n\t\tSTEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)\n\n/* Round 3 */\n\t\tSTEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)\n\t\tSTEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)\n\t\tSTEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)\n\t\tSTEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)\n\t\tSTEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)\n\t\tSTEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)\n\t\tSTEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)\n\t\tSTEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)\n\t\tSTEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)\n\t\tSTEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)\n\t\tSTEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)\n\t\tSTEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)\n\t\tSTEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)\n\t\tSTEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)\n\t\tSTEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)\n\t\tSTEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)\n\n/* Round 4 */\n\t\tSTEP(I, a, b, c, d, GET(0), 0xf4292244, 6)\n\t\tSTEP(I, d, a, b, c, GET(7), 0x432aff97, 10)\n\t\tSTEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)\n\t\tSTEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)\n\t\tSTEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)\n\t\tSTEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)\n\t\tSTEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)\n\t\tSTEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)\n\t\tSTEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)\n\t\tSTEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)\n\t\tSTEP(I, c, d, a, b, GET(6), 0xa3014314, 15)\n\t\tSTEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)\n\t\tSTEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)\n\t\tSTEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)\n\t\tSTEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)\n\t\tSTEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)\n\n\t\ta += saved_a;\n\t\tb += saved_b;\n\t\tc += saved_c;\n\t\td += saved_d;\n\n\t\tptr += 64;\n\t} while (size -= 64);\n\n\tctx->a = a;\n\tctx->b = b;\n\tctx->c = c;\n\tctx->d = d;\n\n\treturn ptr;\n}\n\nvoid MD5_Init(MD5_CTX *ctx)\n{\n\tctx->a = 0x67452301;\n\tctx->b = 0xefcdab89;\n\tctx->c = 0x98badcfe;\n\tctx->d = 0x10325476;\n\n\tctx->lo = 0;\n\tctx->hi = 0;\n}\n\nvoid MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)\n{\n\tMD5_u32plus saved_lo;\n\tunsigned long used, available;\n\n\tsaved_lo = ctx->lo;\n\tif ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)\n\t\tctx->hi++;\n\tctx->hi += size >> 29;\n\n\tused = saved_lo & 0x3f;\n\n\tif (used) {\n\t\tavailable = 64 - used;\n\n\t\tif (size < available) {\n\t\t\tmemcpy(&ctx->buffer[used], data, size);\n\t\t\treturn;\n\t\t}\n\n\t\tmemcpy(&ctx->buffer[used], data, available);\n\t\tdata = (const unsigned char *)data + available;\n\t\tsize -= available;\n\t\tbody(ctx, ctx->buffer, 64);\n\t}\n\n\tif (size >= 64) {\n\t\tdata = body(ctx, data, size & ~(unsigned long)0x3f);\n\t\tsize &= 0x3f;\n\t}\n\n\tmemcpy(ctx->buffer, data, size);\n}\n\n#define OUT(dst, src) \\\n\t(dst)[0] = (unsigned char)(src); \\\n\t(dst)[1] = (unsigned char)((src) >> 8); \\\n\t(dst)[2] = (unsigned char)((src) >> 16); \\\n\t(dst)[3] = (unsigned char)((src) >> 24);\n\nvoid MD5_Final(unsigned char *result, MD5_CTX *ctx)\n{\n\tunsigned long used, available;\n\n\tused = ctx->lo & 0x3f;\n\n\tctx->buffer[used++] = 0x80;\n\n\tavailable = 64 - used;\n\n\tif (available < 8) {\n\t\tmemset(&ctx->buffer[used], 0, available);\n\t\tbody(ctx, ctx->buffer, 64);\n\t\tused = 0;\n\t\tavailable = 64;\n\t}\n\n\tmemset(&ctx->buffer[used], 0, available - 8);\n\n\tctx->lo <<= 3;\n\tOUT(&ctx->buffer[56], ctx->lo)\n\tOUT(&ctx->buffer[60], ctx->hi)\n\n\tbody(ctx, ctx->buffer, 64);\n\n\tOUT(&result[0], ctx->a)\n\tOUT(&result[4], ctx->b)\n\tOUT(&result[8], ctx->c)\n\tOUT(&result[12], ctx->d)\n\n\tmemset(ctx, 0, sizeof(*ctx));\n}\n\nvoid MD5(const void *data, unsigned long size, unsigned char *result) {\n\tMD5_CTX ctx;\n\tMD5_Init(&ctx);\n\tMD5_Update(&ctx, data, size);\n\tMD5_Final(result, &ctx);\n}\n\n#endif\n"
  },
  {
    "path": "libs/md5.h",
    "content": "/*\n * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.\n * MD5 Message-Digest Algorithm (RFC 1321).\n *\n * Homepage:\n * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5\n *\n * Author:\n * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>\n *\n * This software was written by Alexander Peslyak in 2001.  No copyright is\n * claimed, and the software is hereby placed in the public domain.\n * In case this attempt to disclaim copyright and place the software in the\n * public domain is deemed null and void, then the software is\n * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the\n * general public under the following terms:\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted.\n *\n * There's ABSOLUTELY NO WARRANTY, express or implied.\n *\n * See md5.c for more information.\n */\n\n#ifdef HAVE_OPENSSL\n#include <openssl/md5.h>\n#elif !defined(_MD5_H)\n#define _MD5_H\n\n/* Any 32-bit or wider unsigned integer data type will do */\ntypedef unsigned int MD5_u32plus;\n\ntypedef struct {\n\tMD5_u32plus lo, hi;\n\tMD5_u32plus a, b, c, d;\n\tunsigned char buffer[64];\n\tMD5_u32plus block[16];\n} MD5_CTX;\n\nextern void MD5_Init(MD5_CTX *ctx);\nextern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);\nextern void MD5_Final(unsigned char *result, MD5_CTX *ctx);\n\nvoid MD5(const void *data, unsigned long size, unsigned char *result);\n\n#endif\n"
  },
  {
    "path": "libs/sha1.c",
    "content": "\n/* from valgrind tests */\n\n/* ================ sha1.c ================ */\n/*\nSHA-1 in C\nBy Steve Reid <steve@edmweb.com>\n100% Public Domain\n\nTest Vectors (from FIPS PUB 180-1)\n\"abc\"\n  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D\n\"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq\"\n  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1\nA million repetitions of \"a\"\n  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F\n*/\n\n/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */\n/* #define SHA1HANDSOFF * Copies data before messing with it. */\n\n#define SHA1HANDSOFF\n\n#include <stdio.h>\n#include <string.h>\n#include <stdint.h>\n#include \"sha1.h\"\n\n#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))\n\n/* blk0() and blk() perform the initial expand. */\n/* I got the idea of expanding during the round function from SSLeay */\n#if BYTE_ORDER == LITTLE_ENDIAN\n#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \\\n    |(rol(block->l[i],8)&0x00FF00FF))\n#elif BYTE_ORDER == BIG_ENDIAN\n#define blk0(i) block->l[i]\n#else\n#error \"Endianness not defined!\"\n#endif\n#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \\\n    ^block->l[(i+2)&15]^block->l[i&15],1))\n\n/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */\n#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);\n#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);\n#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);\n#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);\n#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);\n\n\n/* Hash a single 512-bit block. This is the core of the algorithm. */\n\nvoid SHA1Transform(uint32_t state[5], const unsigned char buffer[64])\n{\n    uint32_t a, b, c, d, e;\n    typedef union {\n        unsigned char c[64];\n        uint32_t l[16];\n    } CHAR64LONG16;\n#ifdef SHA1HANDSOFF\n    CHAR64LONG16 block[1];  /* use array to appear as a pointer */\n    memcpy(block, buffer, 64);\n#else\n    /* The following had better never be used because it causes the\n     * pointer-to-const buffer to be cast into a pointer to non-const.\n     * And the result is written through.  I threw a \"const\" in, hoping\n     * this will cause a diagnostic.\n     */\n    CHAR64LONG16* block = (const CHAR64LONG16*)buffer;\n#endif\n    /* Copy context->state[] to working vars */\n    a = state[0];\n    b = state[1];\n    c = state[2];\n    d = state[3];\n    e = state[4];\n    /* 4 rounds of 20 operations each. Loop unrolled. */\n    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);\n    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);\n    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);\n    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);\n    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);\n    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);\n    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);\n    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);\n    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);\n    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);\n    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);\n    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);\n    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);\n    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);\n    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);\n    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);\n    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);\n    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);\n    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);\n    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);\n    /* Add the working vars back into context.state[] */\n    state[0] += a;\n    state[1] += b;\n    state[2] += c;\n    state[3] += d;\n    state[4] += e;\n    /* Wipe variables */\n    a = b = c = d = e = 0;\n#ifdef SHA1HANDSOFF\n    memset(block, '\\0', sizeof(block));\n#endif\n}\n\n\n/* SHA1Init - Initialize new context */\n\nvoid SHA1Init(SHA1_CTX* context)\n{\n    /* SHA1 initialization constants */\n    context->state[0] = 0x67452301;\n    context->state[1] = 0xEFCDAB89;\n    context->state[2] = 0x98BADCFE;\n    context->state[3] = 0x10325476;\n    context->state[4] = 0xC3D2E1F0;\n    context->count[0] = context->count[1] = 0;\n}\n\n\n/* Run your data through this. */\n\nvoid SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len)\n{\n    uint32_t i, j;\n\n    j = context->count[0];\n    if ((context->count[0] += len << 3) < j)\n        context->count[1]++;\n    context->count[1] += (len>>29);\n    j = (j >> 3) & 63;\n    if ((j + len) > 63) {\n        memcpy(&context->buffer[j], data, (i = 64-j));\n        SHA1Transform(context->state, context->buffer);\n        for ( ; i + 63 < len; i += 64) {\n            SHA1Transform(context->state, &data[i]);\n        }\n        j = 0;\n    }\n    else i = 0;\n    memcpy(&context->buffer[j], &data[i], len - i);\n}\n\n\n/* Add padding and return the message digest. */\n\nvoid SHA1Final(unsigned char digest[20], SHA1_CTX* context)\n{\n    unsigned i;\n    unsigned char finalcount[8];\n    unsigned char c;\n\n#if 0\t/* untested \"improvement\" by DHR */\n    /* Convert context->count to a sequence of bytes\n     * in finalcount.  Second element first, but\n     * big-endian order within element.\n     * But we do it all backwards.\n     */\n    unsigned char *fcp = &finalcount[8];\n\n    for (i = 0; i < 2; i++)\n       {\n        uint32_t t = context->count[i];\n        int j;\n\n        for (j = 0; j < 4; t >>= 8, j++)\n\t          *--fcp = (unsigned char) t;\n    }\n#else\n    for (i = 0; i < 8; i++) {\n        finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]\n         >> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */\n    }\n#endif\n    c = 0200;\n    SHA1Update(context, &c, 1);\n    while ((context->count[0] & 504) != 448) {\n\tc = 0000;\n        SHA1Update(context, &c, 1);\n    }\n    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */\n    for (i = 0; i < 20; i++) {\n        digest[i] = (unsigned char)\n         ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);\n    }\n    /* Wipe variables */\n    memset(context, '\\0', sizeof(*context));\n    memset(&finalcount, '\\0', sizeof(finalcount));\n}\n/* ================ end of sha1.c ================ */\n\nvoid SHA1(const unsigned char* data, uint32_t len, unsigned char digest[20]) {\n    SHA1_CTX ctx;\n    SHA1Init(&ctx);\n    SHA1Update(&ctx, data, len);\n    SHA1Final(digest, &ctx);\n}"
  },
  {
    "path": "libs/sha1.h",
    "content": "#ifndef SHA1_H\n#define SHA1_H\n/* ================ sha1.h ================ */\n/*\nSHA-1 in C\nBy Steve Reid <steve@edmweb.com>\n100% Public Domain\n*/\n#include <stdint.h>\n\ntypedef struct {\n    uint32_t state[5];\n    uint32_t count[2];\n    unsigned char buffer[64];\n} SHA1_CTX;\n\nvoid SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);\nvoid SHA1Init(SHA1_CTX* context);\nvoid SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len);\nvoid SHA1Final(unsigned char digest[20], SHA1_CTX* context);\n\nvoid SHA1(const unsigned char* data, uint32_t len, unsigned char digest[20]);\n\n#endif\n"
  },
  {
    "path": "main.c",
    "content": "#include <getopt.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"auth.h\"\n#include \"configparse.h\"\n\n#ifdef linux\n#include <limits.h>\n#include \"daemon.h\"\n#include \"eapol.h\"\n#include \"libs/common.h\"\n#endif\n\n#define VERSION \"1.6.2\"\n\nvoid print_help(int exval);\nint try_smart_eaplogin(void);\n\nstatic const char default_bind_ip[20] = \"0.0.0.0\";\n\nint main(int argc, char *argv[]) {\n    if (argc == 1) {\n        print_help(1);\n    }\n\n    char *file_path;\n\n    while (1) {\n        static const struct option long_options[] = {\n            {\"mode\", required_argument, 0, 'm'},\n            {\"conf\", required_argument, 0, 'c'},\n            {\"bindip\", required_argument, 0, 'b'},\n            {\"log\", required_argument, 0, 'l'},\n#ifdef linux\n            {\"daemon\", no_argument, 0, 'd'},\n            {\"802.1x\", no_argument, 0, 'x'},\n#endif\n            {\"eternal\", no_argument, 0, 'e'},\n            {\"verbose\", no_argument, 0, 'v'},\n            {\"help\", no_argument, 0, 'h'},\n            {0, 0, 0, 0}};\n\n        int c;\n        int option_index = 0;\n#ifdef linux\n        c = getopt_long(argc, argv, \"m:c:b:l:dxevh\", long_options, &option_index);\n#else\n        c = getopt_long(argc, argv, \"m:c:b:l:evh\", long_options, &option_index);\n#endif\n\n        if (c == -1) {\n            break;\n        }\n        switch (c) {\n            case 'm':\n                if (strcmp(optarg, \"dhcp\") == 0) {\n                    strcpy(mode, optarg);\n                } else if (strcmp(optarg, \"pppoe\") == 0) {\n                    strcpy(mode, optarg);\n                } else {\n                    printf(\"unknown mode\\n\");\n                    exit(1);\n                }\n                break;\n            case 'c':\n#ifndef __APPLE__\n                if (mode != NULL) {\n#endif\n#ifdef linux\n                    char path_c[PATH_MAX];\n                    realpath(optarg, path_c);\n                    file_path = strdup(path_c);\n#else\n                file_path = optarg;\n#endif\n#ifndef __APPLE__\n                }\n#endif\n                break;\n            case 'b':\n                strcpy(bind_ip, optarg);\n                break;\n            case 'l':\n#ifndef __APPLE__\n                if (mode != NULL) {\n#endif\n#ifdef linux\n                    char path_l[PATH_MAX];\n                    realpath(optarg, path_l);\n                    log_path = strdup(path_l);\n#else\n                log_path = optarg;\n#endif\n                    logging_flag = 1;\n#ifndef __APPLE__\n                }\n#endif\n                break;\n#ifdef linux\n            case 'd':\n                daemon_flag = 1;\n                break;\n            case 'x':\n                eapol_flag = 1;\n                break;\n#endif\n            case 'e':\n                eternal_flag = 1;\n                break;\n            case 'v':\n                verbose_flag = 1;\n                break;\n            case 'h':\n                print_help(0);\n                break;\n            case '?':\n                print_help(1);\n                break;\n            default:\n                break;\n        }\n    }\n\n#ifndef __APPLE__\n    if (mode != NULL && file_path != NULL) {\n#endif\n#ifdef linux\n        if (daemon_flag) {\n            daemonise();\n        }\n#endif\n\n#ifdef WIN32  // dirty fix with win32\n        char tmp[10] = {0};\n        strcpy(tmp, mode);\n#endif\n        if (!config_parse(file_path)) {\n#ifdef WIN32  // dirty fix with win32\n            strcpy(mode, tmp);\n#endif\n\n#ifdef linux\n            if (eapol_flag) {  // eable 802.1x authorization\n                if (0 != try_smart_eaplogin()) {\n                    printf(\"Can't finish 802.1x authorization!\\n\");\n                    return 1;\n                }\n            }\n#endif\n            if (strlen(bind_ip) == 0) {\n                memcpy(bind_ip, default_bind_ip, sizeof(default_bind_ip));\n            }\n            dogcom(5);\n        } else {\n            return 1;\n        }\n#ifndef __APPLE__\n    } else {\n        printf(\"Need more options!\\n\\n\");\n        return 1;\n    }\n#endif\n    return 0;\n}\n\nvoid print_help(int exval) {\n    printf(\"\\nDrcom-generic implementation in C.\\n\");\n    printf(\"Version: %s\\n\\n\", VERSION);\n\n    printf(\"Usage:\\n\");\n    printf(\"\\tdogcom -m <dhcp/pppoe> -c <FILEPATH> [options <argument>]...\\n\\n\");\n\n    printf(\"Options:\\n\");\n    printf(\"\\t--mode <dhcp/pppoe>, -m <dhcp/pppoe>  set your dogcom mode \\n\");\n    printf(\"\\t--conf <FILEPATH>, -c <FILEPATH>      import configuration file\\n\");\n    printf(\"\\t--bindip <IPADDR>, -b <IPADDR>        bind your ip address(default is 0.0.0.0)\\n\");\n    printf(\"\\t--log <LOGPATH>, -l <LOGPATH>         specify log file\\n\");\n#ifdef linux\n    printf(\"\\t--daemon, -d                          set daemon flag\\n\");\n    printf(\"\\t--802.1x, -x                          enable 802.1x\\n\");\n#endif\n    printf(\"\\t--eternal, -e                         set eternal flag\\n\");\n    printf(\"\\t--verbose, -v                         set verbose flag\\n\");\n    printf(\"\\t--help, -h                            display this help\\n\\n\");\n    exit(exval);\n}\n\n#ifdef linux\nint try_smart_eaplogin(void) {\n#define IFS_MAX (64)\n    int ifcnt = IFS_MAX;\n    iflist_t ifs[IFS_MAX];\n    if (0 > getall_ifs(ifs, &ifcnt))\n        return -1;\n\n    for (int i = 0; i < ifcnt; ++i) {\n        setifname(ifs[i].name);\n        if (0 == eaplogin(drcom_config.username, drcom_config.password))\n            return 0;\n    }\n    return -1;\n}\n#endif"
  },
  {
    "path": "sample-d.conf",
    "content": "server = '192.168.1.14'\nusername = 'a'\npassword = 'a'\nCONTROLCHECKSTATUS = '\\x20'\nADAPTERNUM = '\\x01'\nhost_ip = '10.30.22.17'\nIPDOG = '\\x01'\nhost_name = 'LIYUANYUAN'\nPRIMARY_DNS = '114.114.114.114'\ndhcp_server = '0.0.0.0'\nAUTH_VERSION = '\\x0A\\x00'\nmac = 0xb888e3051680\nhost_os = '8089D'\nKEEP_ALIVE_VERSION = '\\xDC\\x02'\nror_version = True\nkeepalive1_mod = True"
  },
  {
    "path": "sample-p.conf",
    "content": "server = '192.168.1.14'\npppoe_flag = '\\x18'\nkeep_alive2_flag = '\\xd8'"
  }
]