Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b11db84072 | |||
| ad0b0d6910 | |||
| e3509c3152 | |||
| 9f8f19dbfe | |||
| a224104188 | |||
| 7de356fa85 | |||
| fd186fe50a | |||
| 67a36b150d | |||
| 62417c9201 | |||
| 5c36b6fea4 | |||
| 15ec840544 | |||
| 782debcd74 | |||
| ddb8297bc3 | |||
| 6569e7e577 | |||
| d439dbc26d | |||
| b97b4b212e |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
*.o
|
||||||
|
denyip
|
||||||
17
.vscode/c_cpp_properties.json
vendored
Normal file
17
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"compilerPath": "/usr/bin/gcc",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "gnu++17",
|
||||||
|
"intelliSenseMode": "linux-gcc-x64",
|
||||||
|
"configurationProvider": "ms-vscode.makefile-tools"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
5
.vscode/extensions.json
vendored
Normal file
5
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"alibaba-cloud.tongyi-lingma"
|
||||||
|
]
|
||||||
|
}
|
||||||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@@ -1,13 +1,10 @@
|
|||||||
{
|
{
|
||||||
"C_Cpp.errorSquiggles": "disabled",
|
"C_Cpp.errorSquiggles": "disabled",
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"string.h": "c",
|
|
||||||
"stdlib.h": "c",
|
|
||||||
"ip2region.h": "c",
|
|
||||||
"common.h": "c",
|
"common.h": "c",
|
||||||
"prctl.h": "c",
|
"prctl.h": "c",
|
||||||
"resource.h": "c",
|
"algorithm": "c",
|
||||||
"wait.h": "c",
|
"cstdlib": "c",
|
||||||
"stdio.h": "c"
|
"libipset.h": "c"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -5,18 +5,22 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IPInfo struct {
|
type IPInfo struct {
|
||||||
Code string `json:"code"`
|
Msg string `json:"msg"`
|
||||||
Data struct {
|
Data struct {
|
||||||
Continent string `json:"continent"`
|
Continent string `json:"continent"`
|
||||||
Country string `json:"country"`
|
Country string `json:"country"`
|
||||||
} `json:"data"`
|
} `json:"data"`
|
||||||
IP string `json:"ip"`
|
}
|
||||||
Msg string `json:"msg"`
|
|
||||||
|
func isValidIP(ip string) bool {
|
||||||
|
return net.ParseIP(ip) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -24,16 +28,29 @@ func main() {
|
|||||||
log.Fatalf("用法: %s <IP>", os.Args[0])
|
log.Fatalf("用法: %s <IP>", os.Args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ip := os.Args[1]
|
||||||
|
if !isValidIP(ip) {
|
||||||
|
log.Fatalf("无效的 IP 地址: %s", ip)
|
||||||
|
}
|
||||||
|
|
||||||
// 目标 URL
|
// 目标 URL
|
||||||
url := "https://qifu.baidu.com/ip/geo/v1/district?ip=" + os.Args[1]
|
url := "https://qifu.baidu.com/ip/geo/v1/district?ip=" + ip
|
||||||
|
|
||||||
|
// 创建 HTTP 客户端并设置超时时间
|
||||||
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
|
|
||||||
// 发送 GET 请求
|
// 发送 GET 请求
|
||||||
resp, err := http.Get(url)
|
resp, err := client.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("发送 GET 请求时出错: %v", err)
|
log.Fatalf("发送 GET 请求时出错: %v", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// 检查 HTTP 响应状态码
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
log.Fatalf("HTTP 请求失败,状态码: %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
// 读取响应体
|
// 读取响应体
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
339
LICENSE
Normal file
339
LICENSE
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
{description}
|
||||||
|
Copyright (C) {year} {fullname}
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
{signature of Ty Coon}, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License.
|
||||||
60
Makefile
60
Makefile
@@ -1,21 +1,71 @@
|
|||||||
CROSS_COMPILE ?=
|
CROSS_COMPILE ?=
|
||||||
CC := $(CROSS_COMPILE)gcc
|
CC := $(CROSS_COMPILE)gcc
|
||||||
STRIP := $(CROSS_COMPILE)strip
|
STRIP := $(CROSS_COMPILE)strip
|
||||||
CFLAGS += -g -Os -Wall -Iip2region -Iqqwry
|
CFLAGS += -g -Wall -Iip2region
|
||||||
LIBS = -lm -static
|
LIBS =
|
||||||
BIN := denyip
|
BIN := denyip
|
||||||
|
|
||||||
|
|
||||||
|
# 检测操作系统并设置相应的变量
|
||||||
|
OS := $(shell if cat /etc/issue | grep -i 'ubuntu' >/dev/null 2>&1; then \
|
||||||
|
echo ubuntu; \
|
||||||
|
elif test -f /etc/debian_version; then \
|
||||||
|
echo debian; \
|
||||||
|
elif test -f /etc/centos-release; then \
|
||||||
|
echo centos; \
|
||||||
|
else \
|
||||||
|
echo unsupported; \
|
||||||
|
fi)
|
||||||
|
|
||||||
|
OS_VER := $(shell if [ "$(OS)" = "ubuntu" ]; then \
|
||||||
|
cat /etc/issue | head -n1 | awk '{print $$2}'; \
|
||||||
|
elif [ "$(OS)" = "debian" ]; then \
|
||||||
|
cat /etc/debian_version; \
|
||||||
|
elif [ "$(OS)" = "centos" ]; then \
|
||||||
|
cat /etc/centos-release | grep -o -E '[0-9.]{3,}' 2>/dev/null; \
|
||||||
|
else \
|
||||||
|
echo "N/A"; \
|
||||||
|
fi)
|
||||||
|
|
||||||
|
KERNEL := $(shell uname -sr)
|
||||||
|
ARCH := $(shell uname -m)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 使用shell命令获取库的链接选项
|
||||||
|
ifeq ($(OS), centos)
|
||||||
|
LIBPCAP := /usr/lib64/libpcap.so
|
||||||
|
LIBS =
|
||||||
|
else
|
||||||
|
LIBPCAP := $(shell pkg-config --libs --static libpcap)
|
||||||
|
endif
|
||||||
|
LIBCAP := $(shell pkg-config --libs --static libcap)
|
||||||
|
LIBIPSET := $(shell pkg-config --libs --static libipset)
|
||||||
|
|
||||||
all: $(BIN) # 默认目标
|
all: $(BIN) # 默认目标
|
||||||
|
|
||||||
|
# 系统信息打印目标
|
||||||
|
info:
|
||||||
|
@echo "Operating System: $(OS)"
|
||||||
|
@echo "OS Version: $(OS_VER)"
|
||||||
|
@echo "Kernel Version: $(KERNEL)"
|
||||||
|
@echo "Architecture: $(ARCH)"
|
||||||
|
@echo "Compiler: $(CC)"
|
||||||
|
@echo "CFLAGS: $(CFLAGS)"
|
||||||
|
@echo "Libraries: $(LIBS)"
|
||||||
|
@echo "LIBPCAP: $(LIBPCAP)"
|
||||||
|
@echo "LIBCAP: $(LIBCAP)"
|
||||||
|
@echo "LIBIPSET: $(LIBIPSET)"
|
||||||
|
|
||||||
ipquery: # Go 构建目标
|
ipquery: # Go 构建目标
|
||||||
cd IP_region_query && CGO_ENABLED=0 go build -ldflags '-w -s'
|
cd IP_region_query && CGO_ENABLED=0 go build -ldflags '-w -s'
|
||||||
|
|
||||||
$(BIN): main.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o qqwry/qqwry.o
|
$(BIN): cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o
|
||||||
$(CC) $(CFLAGS) -o $(BIN) $^ $(LIBS)
|
$(CC) $(CFLAGS) -o $(BIN) $^ $(LIBPCAP) $(LIBCAP) $(LIBIPSET) $(LIBS)
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CFLAGS) -c $< -o $@
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(BIN) ipquery
|
rm -rf $(BIN) ipquery
|
||||||
rm -rf main.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o qqwry/qqwry.o
|
rm -rf cap.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o libipset.o
|
||||||
|
|||||||
141
README.md
141
README.md
@@ -1,47 +1,112 @@
|
|||||||
# denyip
|
# DenyIP
|
||||||
|
|
||||||
大陆服务器禁止国外IP访问
|
## 概述
|
||||||
|
|
||||||
## build
|
`DenyIP` 是一个用于保护大陆服务器免受非本地业务访问的防火墙工具。通过结合 `libpcap`、`libipset`、`ip2region` 和 `Go ipquery`,该工具能够高效地捕获网络数据包、提取源IP地址、进行地理位置判断,并将非大陆IP地址添加到IP黑名单中,从而严格限制非大陆来源的访问。
|
||||||
|
|
||||||
~~~bash
|
## 特点
|
||||||
# Debian System
|
|
||||||
apt install build-essential
|
|
||||||
apt install golang
|
|
||||||
apt install tcpdump procps iptables ipset
|
|
||||||
|
|
||||||
root@NIUYULING:/mnt/c/Users/root/Desktop/git.aixiao.me/DenyIP# make clean; make
|
- **数据包捕获**:使用 `libpcap` 捕获网络数据包,提取源IP地址。
|
||||||
rm -rf denyip ipquery
|
- **IP黑名单管理**:使用 `libipset` 管理IP黑名单,高效存储和匹配IP地址。
|
||||||
rm -rf main.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o qqwry/qqwry.o
|
- **初步IP地域判定**:使用 `ip2region` 库进行初步的IP地理位置判断。
|
||||||
gcc -g -Os -Wall -Iip2region -Iqqwry -c main.c -o main.o
|
- **精确IP地理位置判断**:使用 `Go ipquery` 进一步精准识别IP地理位置。
|
||||||
gcc -g -Os -Wall -Iip2region -Iqqwry -c common.c -o common.o
|
- **灵活的命令行选项**:支持守护进程模式、指定网络接口、启用/禁用Iptables规则等。
|
||||||
gcc -g -Os -Wall -Iip2region -Iqqwry -c ip2region/ip2region.c -o ip2region/ip2region.o
|
|
||||||
gcc -g -Os -Wall -Iip2region -Iqqwry -c ip2region/xdb_searcher.c -o ip2region/xdb_searcher.o
|
|
||||||
gcc -g -Os -Wall -Iip2region -Iqqwry -c qqwry/qqwry.c -o qqwry/qqwry.o
|
|
||||||
gcc -g -Os -Wall -Iip2region -Iqqwry -o denyip main.o common.o ip2region/ip2region.o ip2region/xdb_searcher.o qqwry/qqwry.o -lm -static
|
|
||||||
root@NIUYULING:/mnt/c/Users/root/Desktop/git.aixiao.me/DenyIP#
|
|
||||||
~~~
|
|
||||||
|
|
||||||
### help
|
## 安装
|
||||||
|
|
||||||
~~~bash
|
### 依赖项
|
||||||
|
|
||||||
root@NIUYULING:/mnt/c/Users/root/Desktop/git.aixiao.me/DenyIP# ./denyip -h
|
在 Debian 系统上安装所需的开发工具和库:
|
||||||
DenyIp
|
|
||||||
Linux system firewall, reject non-Chinese IP
|
```bash
|
||||||
Email: aixiao@aixiao.me
|
sudo apt update
|
||||||
Version: 0.1
|
sudo apt install build-essential golang libpcap-dev libcap-dev libipset-dev libsystemd-dev
|
||||||
Usage: ./denyip [-i eth0|-h|-?] [start|stop]
|
```
|
||||||
Options:
|
|
||||||
stop Enable firewall rules
|
在 Centos 7 系统上安装所需的开发工具和库:
|
||||||
start Disable firewall rules
|
|
||||||
Parameters:
|
```bash
|
||||||
-h|? Help info
|
yum install ipset-devel libattr-devel libpcap-devel libcap-devel
|
||||||
-i interface name
|
```
|
||||||
|
|
||||||
|
### 下载项目
|
||||||
|
|
||||||
|
克隆项目仓库:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.aixiao.me/DenyIP.git
|
||||||
|
cd DenyIP
|
||||||
|
```
|
||||||
|
|
||||||
|
## 构建
|
||||||
|
|
||||||
|
编译项目:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make clean
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 命令行选项
|
||||||
|
|
||||||
|
```bash
|
||||||
|
Usage: denyip [-d] [-i <interface>] [-s <start|stop>] [-h|-?]
|
||||||
|
-d Daemon mode
|
||||||
|
-i interface (default eth0)
|
||||||
|
-s regular signal (default start|stop)
|
||||||
|
start Enable Iptables rule
|
||||||
|
stop Disable Iptables rule
|
||||||
|
-h|-? Help Information
|
||||||
|
```
|
||||||
|
|
||||||
|
### 示例命令
|
||||||
|
|
||||||
|
- **启动守护进程**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./denyip -d -i eth0
|
||||||
|
```
|
||||||
|
|
||||||
|
- **启用Iptables规则**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./denyip -s start
|
||||||
|
```
|
||||||
|
|
||||||
|
- **禁用Iptables规则**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./denyip -s stop
|
||||||
|
```
|
||||||
|
|
||||||
|
- **查看帮助信息**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./denyip -h
|
||||||
|
```
|
||||||
|
|
||||||
|
- **关闭守护进程**:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
killall -15 denyip
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
root@niuyuling:~/DenyIP# killall denyip # 关闭
|
## 贡献
|
||||||
root@niuyuling:~/DenyIP# ./denyip -i eth0 # 启动
|
|
||||||
root@niuyuling:~/DenyIP# ./denyip start # Iptables 规则打开
|
欢迎贡献代码和提出改进建议!请通过 Pull Request 或 Issue 的方式提交。
|
||||||
root@niuyuling:~/DenyIP# ./denyip stop # Iptables 规则关闭
|
|
||||||
~~~
|
## 联系信息
|
||||||
|
|
||||||
|
- **邮箱**:<aixiao@aixiao.me>
|
||||||
|
- **日期**:20241024
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
本项目遵循 GNU 许可证,详情参见 [LICENSE](LICENSE) 文件。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
希望这个 `README.md` 文件能够帮助您更好地介绍和使用 `DenyIP` 项目。如果有任何其他需求或修改,请随时告知。
|
||||||
453
cap.c
Normal file
453
cap.c
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
#include "cap.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "libipset.h"
|
||||||
|
|
||||||
|
|
||||||
|
pcap_if_t *alldevs, *device;
|
||||||
|
pcap_t *handle; // 会话句柄
|
||||||
|
struct bpf_program fp; // 编译后的过滤器
|
||||||
|
|
||||||
|
pid_t pid = -1; // 子进程全局PID
|
||||||
|
|
||||||
|
#define SHM_SIZE 1024 // 共享内存大小
|
||||||
|
#define SHM_KEY 0124 // 共享内存键值
|
||||||
|
int shmid = -1;
|
||||||
|
int RULE_NAME_NUMBER = 0; // ipset 集合集合数
|
||||||
|
char *RULE_NAME = NULL; // 共享内存
|
||||||
|
char *ip2region_area = NULL; // ip2region 解析结果
|
||||||
|
char *command_result = NULL; // 执行命令的结果
|
||||||
|
|
||||||
|
#define CACHE_TTL 600 // 设定缓存的存活时间为 600 秒 (10 分钟)
|
||||||
|
#define MAX_CACHE_SIZE 100 // 缓存最多存储 100 个 IP 地址
|
||||||
|
struct ip_cache_node *ip_cache_head = NULL; // 缓存链表的头节点
|
||||||
|
int cache_size = 0; // 当前缓存中的 IP 数量
|
||||||
|
|
||||||
|
// 定义链表结构,用于缓存 IP 地址
|
||||||
|
struct ip_cache_node {
|
||||||
|
char ip[INET_ADDRSTRLEN]; // 存储 IP 地址
|
||||||
|
time_t timestamp; // 记录缓存时间
|
||||||
|
struct ip_cache_node *next; // 指向下一个节点
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 检查 IP 是否已在缓存中并是否过期
|
||||||
|
int is_ip_in_cache(const char *ip)
|
||||||
|
{
|
||||||
|
time_t now = time(NULL); // 获取当前时间
|
||||||
|
struct ip_cache_node *current = ip_cache_head;
|
||||||
|
struct ip_cache_node *prev = NULL;
|
||||||
|
|
||||||
|
while (current != NULL) {
|
||||||
|
// 如果 IP 匹配并且未过期
|
||||||
|
if (strcmp(current->ip, ip) == 0) {
|
||||||
|
if (now - current->timestamp <= CACHE_TTL) {
|
||||||
|
return 1; // IP 在缓存中,且未过期
|
||||||
|
} else {
|
||||||
|
// 如果过期,从链表中移除这个节点
|
||||||
|
if (prev == NULL) {
|
||||||
|
ip_cache_head = current->next;
|
||||||
|
} else {
|
||||||
|
prev->next = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(current);
|
||||||
|
cache_size--;
|
||||||
|
return 0; // IP 过期,不再缓存
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = current;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
return 0; // IP 不在缓存中
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将新 IP 添加到缓存,若缓存过大则移除最早的 IP
|
||||||
|
void add_ip_to_cache(const char *ip)
|
||||||
|
{
|
||||||
|
// 如果缓存大小超过限制,移除最早的 IP
|
||||||
|
if (cache_size >= MAX_CACHE_SIZE) {
|
||||||
|
struct ip_cache_node *current = ip_cache_head;
|
||||||
|
struct ip_cache_node *prev = NULL;
|
||||||
|
|
||||||
|
// 找到链表的最后一个节点
|
||||||
|
while (current->next != NULL) {
|
||||||
|
prev = current;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除最后一个节点(最早的 IP)
|
||||||
|
if (prev != NULL) {
|
||||||
|
prev->next = NULL;
|
||||||
|
} else {
|
||||||
|
ip_cache_head = NULL;
|
||||||
|
}
|
||||||
|
free(current);
|
||||||
|
cache_size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的缓存节点并添加到链表头部
|
||||||
|
struct ip_cache_node *new_node = (struct ip_cache_node *)malloc(sizeof(struct ip_cache_node));
|
||||||
|
if (new_node == NULL) {
|
||||||
|
perror("malloc");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strncpy(new_node->ip, ip, INET_ADDRSTRLEN);
|
||||||
|
new_node->timestamp = time(NULL); // 记录当前时间
|
||||||
|
new_node->next = ip_cache_head;
|
||||||
|
ip_cache_head = new_node;
|
||||||
|
cache_size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理缓存链表,释放所有节点的内存
|
||||||
|
void free_ip_cache()
|
||||||
|
{
|
||||||
|
struct ip_cache_node *current = ip_cache_head;
|
||||||
|
while (current != NULL) {
|
||||||
|
struct ip_cache_node *next = current->next;
|
||||||
|
free(current);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_cache_head = NULL;
|
||||||
|
cache_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回调函数,在捕获到每个数据包时调用
|
||||||
|
void packet_handler(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
|
||||||
|
{
|
||||||
|
int ethernet_header_len = 14;
|
||||||
|
struct ip *ip_header = (struct ip *)(packet + ethernet_header_len);
|
||||||
|
char src_ip[INET_ADDRSTRLEN] = { 0 };
|
||||||
|
|
||||||
|
// 地域白名单
|
||||||
|
char _region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
|
||||||
|
char _REGION_LIST[BUFFER] = { 0 };
|
||||||
|
const char *REGION_ENV = NULL;
|
||||||
|
|
||||||
|
int r = 0;
|
||||||
|
//char *t = _time();
|
||||||
|
|
||||||
|
inet_ntop(AF_INET, &(ip_header->ip_src), src_ip, INET_ADDRSTRLEN);
|
||||||
|
//_printf("%s\n", src_ip);
|
||||||
|
|
||||||
|
|
||||||
|
// 如果 IP 地址已在缓存中且未过期,则跳过查询
|
||||||
|
if (is_ip_in_cache(src_ip)) {
|
||||||
|
_printf(RED "IP:%s 已在缓存中,跳过查询\n" REDEND, src_ip);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 执行查询并添加到缓存
|
||||||
|
ip2region_area = ip2region("ip2region/ip2region.xdb", src_ip);
|
||||||
|
if (ip2region_area == NULL) {
|
||||||
|
_printf(RED "ip2region 解析地域错误\n" REDEND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 取环境变量
|
||||||
|
REGION_ENV = getenv("REGION");
|
||||||
|
if (REGION_ENV != NULL) {
|
||||||
|
_printf("REGION: %s\n", REGION_ENV);
|
||||||
|
strcpy(_REGION_LIST, REGION_ENV);
|
||||||
|
} else {
|
||||||
|
strcpy(_REGION_LIST, "局域网 内网 中国 ");
|
||||||
|
}
|
||||||
|
|
||||||
|
split_string(_REGION_LIST, " ", _region_list);
|
||||||
|
if (isregion(ip2region_area, _region_list) == 1) { // 返回1表示在白名单列表
|
||||||
|
;
|
||||||
|
} else {
|
||||||
|
//puts(ip2region_area);
|
||||||
|
|
||||||
|
char ip_query_command[256] = { 0 };
|
||||||
|
snprintf(ip_query_command, sizeof(ip_query_command), "./IP_region_query/ipquery %s", src_ip);
|
||||||
|
if (cache_size < MAX_CACHE_SIZE) // 缓存IP数不够预备设定值
|
||||||
|
{
|
||||||
|
sleep(1);
|
||||||
|
_printf("缓存 IP 数 %d\n", cache_size);
|
||||||
|
}
|
||||||
|
command_result = _execute_command(ip_query_command);
|
||||||
|
if (command_result != NULL) {
|
||||||
|
add_ip_to_cache(src_ip); // 添加 IP 到缓存
|
||||||
|
|
||||||
|
char *p = strstr(command_result, "中国");
|
||||||
|
if (p == NULL) {
|
||||||
|
_printf(RED "%s %s\n" REDEND, src_ip, command_result);
|
||||||
|
r = add_ip_to_ipset(RULE_NAME, src_ip);
|
||||||
|
_printf("add_ip_to_ipset() return %d\n", r);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(command_result);
|
||||||
|
command_result = NULL;
|
||||||
|
} else {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command_result != NULL)
|
||||||
|
free(command_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ip2region_area != NULL)
|
||||||
|
{
|
||||||
|
free(ip2region_area);
|
||||||
|
ip2region_area = NULL;
|
||||||
|
}
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage()
|
||||||
|
{
|
||||||
|
printf("DenyIP version %s\n", _VERSION);
|
||||||
|
puts("拒绝Linux服务器非大陆IP工具");
|
||||||
|
puts("MAIL: aixiao@aixiao.me");
|
||||||
|
puts("Date: 20241024");
|
||||||
|
puts(" Usage: denyip [-d] [-i <interface>] [-s <start|stop>] [-h|-?]");
|
||||||
|
puts(" -d --daemon Daemon mode");
|
||||||
|
puts(" -i --interface interface (default eth0)");
|
||||||
|
puts(" -l print iptables rule");
|
||||||
|
puts(" -s --signal regular signal (default start|stop) ");
|
||||||
|
puts(" start Enable Iptables rule");
|
||||||
|
puts(" stop Disable Iptables rule");
|
||||||
|
puts(" -h|-? Help Information");
|
||||||
|
puts("");
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_(int signum)
|
||||||
|
{
|
||||||
|
|
||||||
|
_printf("Received signal %d, cleaning up...\n", signum);
|
||||||
|
|
||||||
|
// 终止子进程
|
||||||
|
if (pid > 0) {
|
||||||
|
kill(pid, SIGTERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放共享内存
|
||||||
|
if (RULE_NAME != NULL) {
|
||||||
|
shmdt(RULE_NAME);
|
||||||
|
shmctl(shmid, IPC_RMID, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在程序结束时,清理缓存链表
|
||||||
|
free_ip_cache();
|
||||||
|
|
||||||
|
if (ip2region_area != NULL) {
|
||||||
|
free(ip2region_area);
|
||||||
|
ip2region_area = NULL;
|
||||||
|
}
|
||||||
|
if (command_result != NULL) {
|
||||||
|
free(command_result);
|
||||||
|
command_result = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
pcap_freecode(&fp);
|
||||||
|
pcap_freealldevs(alldevs); // 释放设备列表
|
||||||
|
//pcap_close(handle); // 关闭会话句柄
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 退出主进程
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
// 注册 SIGTERM 信号处理函数
|
||||||
|
signal(SIGTERM, cleanup_);
|
||||||
|
|
||||||
|
int opt;
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE]; // 错误缓冲区
|
||||||
|
char protocol[] = "tcp";
|
||||||
|
char interface[256] = "{ 0 }";
|
||||||
|
char Ipset_Command[BUFFER];
|
||||||
|
|
||||||
|
strcpy(interface, "eth0");
|
||||||
|
memset(&alldevs, 0, sizeof(alldevs));
|
||||||
|
memset(&device, 0, sizeof(device));
|
||||||
|
memset(errbuf, 0, PCAP_ERRBUF_SIZE);
|
||||||
|
|
||||||
|
int longindex = 0;
|
||||||
|
char optstring[] = "di:s:lh?";
|
||||||
|
static struct option longopts[] = {
|
||||||
|
{ "interface", required_argument, 0, 'i' },
|
||||||
|
{ "signal", required_argument, 0, 's' },
|
||||||
|
{ "daemon", no_argument, 0, 'd' },
|
||||||
|
{ "l", no_argument, 0, 'l' },
|
||||||
|
{ "help", no_argument, 0, 'h' },
|
||||||
|
{ "?", no_argument, 0, '?' },
|
||||||
|
{ 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
while (-1 != (opt = getopt_long(argc, argv, optstring, longopts, &longindex)))
|
||||||
|
{
|
||||||
|
switch (opt) {
|
||||||
|
case 'd':
|
||||||
|
if (daemon(1, 1)) {
|
||||||
|
perror("daemon");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
strcpy(interface, optarg);
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
system("iptables -L -v -n --line-numbers");
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (strcmp(optarg, "start") == 0) {
|
||||||
|
memset(Ipset_Command, 0, BUFFER);
|
||||||
|
// 将 MAXIPSET_RULT_NAME_NUM 替换为实际值
|
||||||
|
snprintf(Ipset_Command, sizeof(Ipset_Command),
|
||||||
|
"for n in $(seq 0 %d); do iptables -A INPUT -p tcp -m set --match-set root$n src -j DROP 2> /dev/null; done",
|
||||||
|
MAXIPSET_RULT_NAME_NUM);
|
||||||
|
system(Ipset_Command);
|
||||||
|
exit(0);
|
||||||
|
} else if (strcmp(optarg, "stop") == 0) {
|
||||||
|
memset(Ipset_Command, 0, BUFFER);
|
||||||
|
// 将 MAXIPSET_RULT_NAME_NUM 替换为实际值
|
||||||
|
snprintf(Ipset_Command, sizeof(Ipset_Command),
|
||||||
|
"for n in $(seq 0 %d); do iptables -D INPUT -p tcp -m set --match-set root$n src -j DROP 2> /dev/null; done",
|
||||||
|
MAXIPSET_RULT_NAME_NUM);
|
||||||
|
system(Ipset_Command);
|
||||||
|
exit(0);
|
||||||
|
} else {
|
||||||
|
usage();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
case '?':
|
||||||
|
usage();
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 创建共享内存
|
||||||
|
shmid = shmget(SHM_KEY, SHM_SIZE, IPC_CREAT | 0666);
|
||||||
|
if (shmid < 0) {
|
||||||
|
perror("shmget");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 连接共享内存到进程地址空间
|
||||||
|
RULE_NAME = (char *)shmat(shmid, NULL, 0);
|
||||||
|
if (RULE_NAME == (char *)-1) {
|
||||||
|
perror("shmat");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pid = fork(); // 创建子进程
|
||||||
|
if (pid == 0) // 子进程
|
||||||
|
{
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
snprintf(RULE_NAME, BUFFER, "root%d", RULE_NAME_NUMBER);
|
||||||
|
|
||||||
|
if (create_ipset(RULE_NAME) != 0) {
|
||||||
|
_printf("创建 IPSet %s 失败\n", RULE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
_printf("子进程当前 Ipset Rule 名 %s\n", RULE_NAME);
|
||||||
|
|
||||||
|
count = get_ip_count_in_ipset(RULE_NAME);
|
||||||
|
if (count >= 0) {
|
||||||
|
_printf("IPSet %s 中的 IP 数量: %d\n", RULE_NAME, count);
|
||||||
|
if (count >= MAXIPSET && RULE_NAME_NUMBER <= MAXIPSET_RULT_NAME_NUM) // RULE_中的IP数量不超过MAXIPSET,并且集合不能超过 MAXIPSET_RULT_NAME_NUM 个
|
||||||
|
{
|
||||||
|
RULE_NAME_NUMBER++;
|
||||||
|
|
||||||
|
snprintf(RULE_NAME, BUFFER, "root%d", RULE_NAME_NUMBER); // 更新规则名称
|
||||||
|
// 创建新的 IPSet
|
||||||
|
if (create_ipset(RULE_NAME) != 0) {
|
||||||
|
_printf("创建 IPSet %s 失败\n", RULE_NAME);
|
||||||
|
} else {
|
||||||
|
char iptables_command[256];
|
||||||
|
sprintf(iptables_command, "iptables -I INPUT -m set --match-set %s src -j DROP", RULE_NAME);
|
||||||
|
system(iptables_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RULE_NAME_NUMBER == MAXIPSET_RULT_NAME_NUM) {
|
||||||
|
_printf("已达到最大规则数限制,停止创建新规则。\n");
|
||||||
|
_printf("请手动清理Ipset规则\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(3); // 每 3 秒检查一次
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 查找可用的网络设备
|
||||||
|
if (pcap_findalldevs(&alldevs, errbuf) == -1) {
|
||||||
|
fprintf(stderr, "无法找到设备: %s\n", errbuf);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打印可用设备列表
|
||||||
|
_printf("可用的设备:\n");
|
||||||
|
for (device = alldevs; device != NULL; device = device->next) {
|
||||||
|
_printf("设备: %s\n", device->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开设备以进行数据包捕获
|
||||||
|
handle = pcap_open_live(interface, BUFSIZ, 1, 1000, errbuf);
|
||||||
|
if (handle == NULL) {
|
||||||
|
fprintf(stderr, "无法打开设备 %s: %s\n", interface, errbuf);
|
||||||
|
pcap_freealldevs(alldevs);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编译过滤器
|
||||||
|
if (pcap_compile(handle, &fp, protocol, 0, PCAP_NETMASK_UNKNOWN) == -1) {
|
||||||
|
fprintf(stderr, "无法编译过滤器 %s: %s\n", protocol, pcap_geterr(handle));
|
||||||
|
pcap_close(handle);
|
||||||
|
pcap_freealldevs(alldevs);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置过滤器
|
||||||
|
if (pcap_setfilter(handle, &fp) == -1) {
|
||||||
|
fprintf(stderr, "无法设置过滤器 %s: %s\n", protocol, pcap_geterr(handle));
|
||||||
|
pcap_freecode(&fp);
|
||||||
|
pcap_close(handle);
|
||||||
|
pcap_freealldevs(alldevs);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始捕获数据包
|
||||||
|
if (pcap_loop(handle, 0, packet_handler, NULL) < 0) {
|
||||||
|
fprintf(stderr, "捕获数据包时出错: %s\n", pcap_geterr(handle));
|
||||||
|
pcap_freecode(&fp);
|
||||||
|
pcap_close(handle);
|
||||||
|
pcap_freealldevs(alldevs);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在程序结束时,清理缓存链表
|
||||||
|
free_ip_cache();
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
pcap_freecode(&fp);
|
||||||
|
pcap_freealldevs(alldevs); // 释放设备列表
|
||||||
|
pcap_close(handle); // 关闭会话句柄
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
31
cap.h
Normal file
31
cap.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef CAP_H
|
||||||
|
#define CAP_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pcap.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/ip.h> // IP header
|
||||||
|
#include <netinet/tcp.h> // TCP header
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
#include <sys/shm.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ip2region/ip2region.h"
|
||||||
|
|
||||||
|
#define RED "\033[31m"
|
||||||
|
#define REDEND "\033[0m"
|
||||||
|
|
||||||
|
#define MAXIPSET 65535
|
||||||
|
#define MAXIPSET_RULT_NAME_NUM 26
|
||||||
|
|
||||||
|
#define _VERSION "0.2"
|
||||||
|
|
||||||
|
#endif
|
||||||
191
common.c
191
common.c
@@ -1,29 +1,31 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
// 计算字符串长度
|
// 计算字符串长度
|
||||||
int _strlen(char *str)
|
int _strlen(const char *str) {
|
||||||
{
|
|
||||||
char *_p = NULL;
|
|
||||||
|
|
||||||
if (str == NULL)
|
if (str == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_p = strchr(str, '\0');
|
const char *_p = strchr(str, '\0');
|
||||||
|
|
||||||
if (_p == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return _p - str;
|
return _p - str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 自定义 printf 函数
|
// 自定义 printf 函数
|
||||||
void my_printf(const char *format, ...)
|
void _printf(const char *format, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
|
|
||||||
// 打印到控制台
|
// 获取当前时间
|
||||||
vprintf(format, args);
|
time_t now = time(NULL);
|
||||||
|
struct tm local_time;
|
||||||
|
localtime_r(&now, &local_time);
|
||||||
|
char time_str[20]; // YYYY-MM-DD HH:MM:SS 格式
|
||||||
|
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &local_time);
|
||||||
|
|
||||||
|
// 打印时间戳到控制台
|
||||||
|
printf("[%s] ", time_str);
|
||||||
|
vprintf(format, args); // 打印内容到控制台
|
||||||
va_end(args); // 结束对变参列表的处理
|
va_end(args); // 结束对变参列表的处理
|
||||||
|
|
||||||
// 重新启动变参列表
|
// 重新启动变参列表
|
||||||
@@ -32,13 +34,6 @@ void my_printf(const char *format, ...)
|
|||||||
// 打开日志文件(追加模式)
|
// 打开日志文件(追加模式)
|
||||||
FILE *log_file = fopen(PRINT_LOG_FILE, "a");
|
FILE *log_file = fopen(PRINT_LOG_FILE, "a");
|
||||||
if (log_file != NULL) {
|
if (log_file != NULL) {
|
||||||
// 获取当前时间
|
|
||||||
time_t now = time(NULL);
|
|
||||||
struct tm local_time;
|
|
||||||
localtime_r(&now, &local_time);
|
|
||||||
char time_str[20]; // YYYY-MM-DD HH:MM:SS 格式
|
|
||||||
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &local_time);
|
|
||||||
|
|
||||||
// 打印时间戳到日志文件
|
// 打印时间戳到日志文件
|
||||||
fprintf(log_file, "[%s] ", time_str);
|
fprintf(log_file, "[%s] ", time_str);
|
||||||
|
|
||||||
@@ -94,7 +89,6 @@ int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM])
|
|||||||
return 0; // 未找到匹配
|
return 0; // 未找到匹配
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 地域段白名单对比
|
// 地域段白名单对比
|
||||||
int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM])
|
int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM])
|
||||||
{
|
{
|
||||||
@@ -117,7 +111,7 @@ int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM])
|
|||||||
return 0; // 没有匹配,返回0
|
return 0; // 没有匹配,返回0
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t copy_new_mem(char *src, int src_len, char **dest)
|
int8_t _copy_new_mem(char *src, int src_len, char **dest)
|
||||||
{
|
{
|
||||||
*dest = (char *)malloc(src_len + 1);
|
*dest = (char *)malloc(src_len + 1);
|
||||||
if (*dest == NULL)
|
if (*dest == NULL)
|
||||||
@@ -128,44 +122,151 @@ int8_t copy_new_mem(char *src, int src_len, char **dest)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *_time()
|
// 返回的时间字符串存储在静态缓冲区中
|
||||||
{
|
char *_time() {
|
||||||
char temp[BUFFER];
|
static char temp[BUFFER];
|
||||||
char *wday[] = { "0", "1", "2", "3", "4", "5", "6" };
|
const char *wday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||||
time_t t;
|
time_t t = time(NULL);
|
||||||
struct tm *p;
|
struct tm *p = localtime(&t);
|
||||||
time(&t);
|
|
||||||
p = localtime(&t); // 取得当地时间
|
|
||||||
|
|
||||||
memset(temp, 0, BUFFER);
|
if (!p) {
|
||||||
snprintf(temp, BUFFER, "[%d/%02d/%02d %s %02d:%02d:%02d] ", (1900 + p->tm_year), (1 + p->tm_mon), p->tm_mday, wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
|
perror("localtime failed");
|
||||||
|
return NULL;
|
||||||
return strdup(temp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snprintf(temp, sizeof(temp), "[%d/%02d/%02d %s %02d:%02d:%02d]",
|
||||||
|
1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday,
|
||||||
|
wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);
|
||||||
|
|
||||||
|
return temp; // 返回静态缓冲区地址
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将字符串转换为IPv4地址
|
||||||
int is_valid_ip(const char *ip)
|
int is_valid_ip(const char *ip)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_in sa;
|
||||||
// 尝试将字符串转换为IPv4地址
|
// 将字符串转换为IPv4地址
|
||||||
int result = inet_pton(AF_INET, ip, &(sa.sin_addr));
|
int result = inet_pton(AF_INET, ip, &(sa.sin_addr));
|
||||||
|
|
||||||
return result != 0;
|
return result != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nice_(int increment)
|
// 修改进程优先级
|
||||||
{
|
int _nice(int increment) {
|
||||||
|
// 获取当前优先级
|
||||||
int oldprio = getpriority(PRIO_PROCESS, getpid());
|
int oldprio = getpriority(PRIO_PROCESS, getpid());
|
||||||
printf("%d\n", oldprio);
|
if (oldprio == -1 && errno != 0) {
|
||||||
|
perror("getpriority failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return setpriority(PRIO_PROCESS, getpid(), oldprio + increment);
|
printf("Current priority: %d\n", oldprio);
|
||||||
|
|
||||||
|
// 检查是否溢出
|
||||||
|
if ((increment > 0 && oldprio > INT_MAX - increment) ||
|
||||||
|
(increment < 0 && oldprio < INT_MIN - increment)) {
|
||||||
|
fprintf(stderr, "Priority overflow error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算新的优先级
|
||||||
|
int newprio = oldprio + increment;
|
||||||
|
|
||||||
|
// 检查新的优先级是否在有效范围内
|
||||||
|
if (newprio < PRIO_MIN || newprio > PRIO_MAX) {
|
||||||
|
fprintf(stderr, "New priority out of range: %d (valid range is %d to %d)\n", newprio, PRIO_MIN, PRIO_MAX);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置新的优先级
|
||||||
|
if (setpriority(PRIO_PROCESS, getpid(), newprio) == -1) {
|
||||||
|
perror("setpriority failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("New priority: %d\n", newprio);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断命令是否存在
|
// 判断命令是否存在
|
||||||
int command_exists(const char *command)
|
int command_exists(const char *command) {
|
||||||
{
|
const char *path_env = getenv("PATH");
|
||||||
char buffer[BUFFER];
|
if (!path_env) {
|
||||||
snprintf(buffer, sizeof(buffer), "%s > /dev/null 2>&1", command);
|
return 0; // 如果 PATH 不存在,返回不存在
|
||||||
int status = system(buffer);
|
|
||||||
|
|
||||||
return (status == 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char filepath[1024]; // 缓冲区大小
|
||||||
|
const char *dir = path_env;
|
||||||
|
|
||||||
|
while (dir && *dir) {
|
||||||
|
// 查找 PATH 中的下一个目录
|
||||||
|
const char *end = strchr(dir, ':');
|
||||||
|
size_t len = end ? (size_t)(end - dir) : strlen(dir);
|
||||||
|
|
||||||
|
// 构建路径并检查长度
|
||||||
|
if (snprintf(filepath, sizeof(filepath), "%.*s/%s", (int)len, dir, command) >= (int)sizeof(filepath)) {
|
||||||
|
return 0; // 缓冲区溢出,返回不存在
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查文件是否存在且可执行
|
||||||
|
if (access(filepath, X_OK) == 0) {
|
||||||
|
puts(filepath);
|
||||||
|
return 1; // 命令存在
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 dir 指针
|
||||||
|
dir = end ? end + 1 : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // 命令不存在
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个函数,执行命令并返回输出
|
||||||
|
char *_execute_command(const char *command) {
|
||||||
|
FILE *fp;
|
||||||
|
char buffer[1024];
|
||||||
|
char *output = NULL;
|
||||||
|
size_t output_size = 0;
|
||||||
|
size_t total_read = 0;
|
||||||
|
|
||||||
|
// 打开管道,执行命令
|
||||||
|
fp = popen(command, "r");
|
||||||
|
if (fp == NULL) {
|
||||||
|
perror("popen");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取命令的输出
|
||||||
|
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
|
||||||
|
size_t len = strlen(buffer);
|
||||||
|
if (total_read + len + 1 > output_size) {
|
||||||
|
output_size = output_size == 0 ? 128 : output_size * 2;
|
||||||
|
char *new_output = realloc(output, output_size);
|
||||||
|
if (new_output == NULL) {
|
||||||
|
perror("realloc");
|
||||||
|
free(output); // 释放已分配的内存
|
||||||
|
pclose(fp); // 关闭管道
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
output = new_output;
|
||||||
|
}
|
||||||
|
// 复制内容并增加总计读取的长度
|
||||||
|
strcpy(output + total_read, buffer);
|
||||||
|
total_read += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保输出以 null 结尾
|
||||||
|
if (output_size > 0) {
|
||||||
|
output[total_read] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭管道
|
||||||
|
if (pclose(fp) == -1) {
|
||||||
|
perror("pclose");
|
||||||
|
free(output); // pclose 失败时释放内存
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
18
common.h
18
common.h
@@ -17,26 +17,30 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
#define PRINT_LOG_FILE "Gateway.log"
|
#define PRINT_LOG_FILE "denyip.log"
|
||||||
#define BUFFER 1024
|
#define BUFFER 1024
|
||||||
#define WHITELIST_IP_NUM 1024
|
#define WHITELIST_IP_NUM 1024
|
||||||
|
|
||||||
extern int _strlen(char *str);
|
|
||||||
extern void my_printf(const char *format, ...);
|
extern char *_time();
|
||||||
|
extern int _strlen(const char *str);
|
||||||
|
extern void _printf(const char *format, ...);
|
||||||
|
extern int _nice(int increment);
|
||||||
|
|
||||||
extern void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM]);
|
extern void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM]);
|
||||||
extern int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM]);
|
extern int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM]);
|
||||||
extern char *_time();
|
|
||||||
extern int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]);
|
extern int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM]);
|
||||||
|
|
||||||
extern int8_t copy_new_mem(char *src, int src_len, char **dest);
|
extern int8_t _copy_new_mem(char *src, int src_len, char **dest);
|
||||||
|
|
||||||
extern int is_valid_ip(const char *ip);
|
extern int is_valid_ip(const char *ip);
|
||||||
extern int nice_(int increment);
|
extern int _command_exists(const char *command);
|
||||||
extern int command_exists(const char *command);
|
extern char *_execute_command(const char *command);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Binary file not shown.
20
ip2region/main.c
Normal file
20
ip2region/main.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include "ip2region.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// 执行查询并添加到缓存
|
||||||
|
char *area = ip2region("ip2region.xdb", "1.1.1.1");
|
||||||
|
if (area == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
puts(area);
|
||||||
|
|
||||||
|
|
||||||
|
free(area);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Binary file not shown.
246
libipset.c
Normal file
246
libipset.c
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
#include "libipset.h"
|
||||||
|
|
||||||
|
// 自定义输出处理函数
|
||||||
|
int custom_output_handler(struct ipset_session *session, void *p, const char *msg, ...)
|
||||||
|
{
|
||||||
|
int *ip_count = (int *)p;
|
||||||
|
char buffer[BUFFER];
|
||||||
|
|
||||||
|
// 格式化输出消息
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
vsnprintf(buffer, sizeof(buffer), msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
// 输出调试信息
|
||||||
|
//printf("Buffer: %s\n", buffer); // 调试输出
|
||||||
|
|
||||||
|
if (strlen(buffer) > 1) {
|
||||||
|
char temp[BUFFER];
|
||||||
|
char *p1 = strstr(buffer, "Number of entries:");
|
||||||
|
if (p1 != NULL) {
|
||||||
|
char *p2 = strstr(p1, "\n");
|
||||||
|
if (p2 != NULL) {
|
||||||
|
size_t len = p2 - p1; // 计算长度
|
||||||
|
if (len < BUFFER) {
|
||||||
|
strncpy(temp, p1, len);
|
||||||
|
temp[len] = '\0'; // 确保字符串结束
|
||||||
|
//puts(temp);
|
||||||
|
|
||||||
|
// 查找冒号并提取数量
|
||||||
|
char *p3 = strstr(temp, ":");
|
||||||
|
if (p3 != NULL) {
|
||||||
|
// 提取数字
|
||||||
|
int count = atoi(p3 + 1); // 从冒号后面开始转换
|
||||||
|
*ip_count += count; // 更新计数
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int custom_output_handler_(struct ipset_session *session, void *p, const char *msg, ...)
|
||||||
|
{
|
||||||
|
char buffer[BUFFER];
|
||||||
|
|
||||||
|
// 格式化输出消息
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
vsnprintf(buffer, sizeof(buffer), msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
// 输出调试信息
|
||||||
|
//printf("Buffer: %s\n", buffer); // 调试输出
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义错误处理函数
|
||||||
|
int custom_error_handler(struct ipset *ipset, void *p, int errnum, const char *msg, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, msg);
|
||||||
|
fprintf(stderr, "自定义错误: ");
|
||||||
|
vfprintf(stderr, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
return 0; // 返回0表示处理成功
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 IPSet,如果它不存在
|
||||||
|
int create_ipset(char *set_name)
|
||||||
|
{
|
||||||
|
struct ipset *ipset = ipset_init();
|
||||||
|
if (!ipset) {
|
||||||
|
fprintf(stderr, "Failed to initialize IPSet\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_load_types();
|
||||||
|
|
||||||
|
struct ipset_session *session = ipset_session(ipset);
|
||||||
|
if (!session) {
|
||||||
|
fprintf(stderr, "Failed to create IPSet session\n");
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置自定义错误和输出处理函数
|
||||||
|
if (ipset_custom_printf(ipset, custom_error_handler, NULL, custom_output_handler_, NULL) != 0) {
|
||||||
|
fprintf(stderr, "设置自定义打印函数失败。\n");
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建集合
|
||||||
|
char *args[] = { "ipset", "create", set_name, "hash:ip", NULL };
|
||||||
|
if (ipset_parse_argv(ipset, 4, args) != 0) {
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ipset_fini(ipset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 向指定的 ipset 添加 IP
|
||||||
|
int add_ip_to_ipset(char *set_name, char *ip)
|
||||||
|
{
|
||||||
|
struct ipset *ipset = NULL;
|
||||||
|
struct ipset_session *session = NULL;
|
||||||
|
|
||||||
|
// 初始化 ipset 和 session
|
||||||
|
ipset = ipset_init();
|
||||||
|
if (!ipset) {
|
||||||
|
fprintf(stderr, "初始化 IPSet 失败\n");
|
||||||
|
return -1; // 返回 -1,但不退出
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_load_types();
|
||||||
|
|
||||||
|
session = ipset_session(ipset);
|
||||||
|
if (!session) {
|
||||||
|
fprintf(stderr, "创建 IPSet 会话失败\n");
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1; // 返回 -1,但不退出
|
||||||
|
}
|
||||||
|
// 设置 IPSet 名称
|
||||||
|
if (ipset_session_data_set(session, IPSET_SETNAME, set_name) != 0) {
|
||||||
|
fprintf(stderr, "设置 IPSet 名称失败\n");
|
||||||
|
ipset_session_fini(session);
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1; // 返回 -1,但不退出
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置自定义错误和输出处理函数
|
||||||
|
if (ipset_custom_printf(ipset, custom_error_handler, NULL, custom_output_handler_, NULL) != 0) {
|
||||||
|
fprintf(stderr, "设置自定义打印函数失败。\n");
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将ip添加到集合
|
||||||
|
char *args[] = { "ipset", "add", set_name, ip, NULL };
|
||||||
|
if (ipset_parse_argv(ipset, 4, args) != 0) {
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ipset_fini(ipset);
|
||||||
|
|
||||||
|
return 0; // 始终返回 0,表示执行成功
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义一个函数来清空指定名称的 ipset 集合
|
||||||
|
int flush_ipset(char *set_name)
|
||||||
|
{
|
||||||
|
struct ipset *ipset = ipset_init();
|
||||||
|
if (!ipset) {
|
||||||
|
fprintf(stderr, "Failed to initialize IPSet\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_load_types();
|
||||||
|
|
||||||
|
// 设置自定义错误和输出处理函数
|
||||||
|
if (ipset_custom_printf(ipset, custom_error_handler, NULL, custom_output_handler_, NULL) != 0) {
|
||||||
|
fprintf(stderr, "设置自定义打印函数失败。\n");
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空集合
|
||||||
|
char *args[] = { "ipset", "flush", set_name, NULL };
|
||||||
|
if (ipset_parse_argv(ipset, 3, args) != 0) {
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("IPSet %s flushed successfully\n", set_name);
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取指定 IPSet 中的 IP 数量
|
||||||
|
int get_ip_count_in_ipset(char *set_name)
|
||||||
|
{
|
||||||
|
int ip_count = 0;
|
||||||
|
struct ipset *ipset = ipset_init();
|
||||||
|
if (!ipset) {
|
||||||
|
fprintf(stderr, "初始化 ipset 失败。\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipset_load_types();
|
||||||
|
|
||||||
|
// 设置自定义错误和输出处理函数
|
||||||
|
if (ipset_custom_printf(ipset, custom_error_handler, NULL, custom_output_handler, &ip_count) != 0) {
|
||||||
|
fprintf(stderr, "设置自定义打印函数失败。\n");
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 列出集合
|
||||||
|
char *args[] = { "ipset", "list", set_name, NULL };
|
||||||
|
if (ipset_parse_argv(ipset, 3, args) != 0) {
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 释放资源
|
||||||
|
ipset_fini(ipset);
|
||||||
|
return ip_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
char *set_name = "root";
|
||||||
|
char *ip = "1.1.1.2";
|
||||||
|
|
||||||
|
// 确保 IPSet 已存在
|
||||||
|
r = create_ipset(set_name);
|
||||||
|
printf("create_ipset %d\n", r);
|
||||||
|
|
||||||
|
r = flush_ipset(set_name);
|
||||||
|
printf("flush_ipset %d\n", r);
|
||||||
|
|
||||||
|
// 尝试添加 IP
|
||||||
|
r = add_ip_to_ipset(set_name, ip);
|
||||||
|
printf("add_ip_to_ipset %d\n", r);
|
||||||
|
|
||||||
|
// 获取并打印 IPSet 中的 IP 数量
|
||||||
|
int count = get_ip_count_in_ipset(set_name);
|
||||||
|
if (count >= 0) {
|
||||||
|
printf("IPSet %s 中的 IP 数量: %d\n", set_name, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
17
libipset.h
Normal file
17
libipset.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef LIBIPSET_H
|
||||||
|
#define LIBIPSET_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include <libipset/ipset.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <arpa/inet.h> // 包含 inet_pton 函数
|
||||||
|
|
||||||
|
#define BUFFER 1024
|
||||||
|
#define MAX_CMD_LENGTH 256 // 或者根据需要调整
|
||||||
|
|
||||||
|
extern int create_ipset( char *set_name);
|
||||||
|
extern int add_ip_to_ipset(char *set_name, char *ip);
|
||||||
|
extern int get_ip_count_in_ipset(char *set_name);
|
||||||
|
|
||||||
|
#endif
|
||||||
315
main.c
315
main.c
@@ -1,315 +0,0 @@
|
|||||||
#include "main.h"
|
|
||||||
|
|
||||||
|
|
||||||
void denyip_help()
|
|
||||||
{
|
|
||||||
puts(" DenyIp");
|
|
||||||
puts("Linux system firewall, reject non-Chinese IP");
|
|
||||||
puts("Email: aixiao@aixiao.me");
|
|
||||||
puts("Version: 0.1");
|
|
||||||
puts("Usage: ./denyip [-i eth0|-h|-?] [start|stop] ");
|
|
||||||
puts("Options:");
|
|
||||||
puts(" stop Enable firewall rules");
|
|
||||||
puts(" start Disable firewall rules");
|
|
||||||
|
|
||||||
puts("Parameters:");
|
|
||||||
puts(" -h|? Help info ");
|
|
||||||
puts(" -i interface name");
|
|
||||||
puts("");
|
|
||||||
puts("");
|
|
||||||
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 处理僵尸进程 */
|
|
||||||
void sigchld_handler(int signal)
|
|
||||||
{
|
|
||||||
while (waitpid(-1, NULL, WNOHANG) > 0) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kill_tcpdump_processes()
|
|
||||||
{
|
|
||||||
int result = system("pkill tcpdump"); // 用 pkill 命令终止所有 tcpdump 进程
|
|
||||||
if (result == -1) {
|
|
||||||
perror("Failed to kill tcpdump processes");
|
|
||||||
}
|
|
||||||
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 进程重启功能
|
|
||||||
void restart_process(pid_t pid1, pid_t pid2, char *argv[])
|
|
||||||
{
|
|
||||||
// 发送 SIGTERM 信号终止两个子进程
|
|
||||||
kill(pid1, SIGTERM);
|
|
||||||
kill(pid2, SIGTERM);
|
|
||||||
|
|
||||||
// 等待子进程完全退出
|
|
||||||
waitpid(pid1, NULL, 0);
|
|
||||||
waitpid(pid2, NULL, 0);
|
|
||||||
|
|
||||||
// 终止 tcpdump 进程
|
|
||||||
kill_tcpdump_processes();
|
|
||||||
|
|
||||||
// 使用 execvp 重新启动程序自身
|
|
||||||
printf("重启进程...\n");
|
|
||||||
execvp(argv[0], argv); // 重新启动程序
|
|
||||||
perror("execvp failed"); // 如果 execvp 出错
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanup_(int signum)
|
|
||||||
{
|
|
||||||
int r;
|
|
||||||
printf("Received signal %d, cleaning up...\n", signum);
|
|
||||||
|
|
||||||
// 终止子进程
|
|
||||||
if (pid1 > 0) {
|
|
||||||
kill(pid1, SIGTERM);
|
|
||||||
}
|
|
||||||
if (pid2 > 0) {
|
|
||||||
kill(pid2, SIGTERM);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 终止所有 tcpdump 进程
|
|
||||||
r = system("pkill tcpdump");
|
|
||||||
if (r == 0) {
|
|
||||||
puts("pkill tcpdump");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 退出主进程
|
|
||||||
exit(0);
|
|
||||||
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
signal(SIGCHLD, sigchld_handler); // 防止子进程变成僵尸进程
|
|
||||||
|
|
||||||
// 主进程设置
|
|
||||||
//prctl(PR_SET_PDEATHSIG, SIGTERM);
|
|
||||||
|
|
||||||
// 注册 SIGTERM 信号处理函数
|
|
||||||
signal(SIGTERM, cleanup_);
|
|
||||||
|
|
||||||
char interface[BUFFER] = { 0 };
|
|
||||||
strcpy(interface, "eth0");
|
|
||||||
|
|
||||||
int r;
|
|
||||||
|
|
||||||
// 参数处理
|
|
||||||
if (argc == 2) {
|
|
||||||
if (0 == strcmp(argv[1], "start")) {
|
|
||||||
if ((r = system("iptables -A INPUT -p tcp -m set --match-set root src -j DROP")) == -1) {
|
|
||||||
puts("\"iptables -A INPUT -p tcp -m set --match-set root src -j DROP\" Error!");
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
} else if (0 == strcmp(argv[1], "stop")) {
|
|
||||||
if ((r = system("iptables -D INPUT -p tcp -m set --match-set root src -j DROP")) == -1) {
|
|
||||||
puts("\"iptables -D INPUT -p tcp -m set --match-set root src -j DROP\" Error!");
|
|
||||||
}
|
|
||||||
exit(0);
|
|
||||||
} else if (0 == strcmp(argv[1], "-h")) {
|
|
||||||
denyip_help();
|
|
||||||
} else if (0 == strcmp(argv[1], "-?")) {
|
|
||||||
denyip_help();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (argc == 3) {
|
|
||||||
if (0 == strcmp(argv[1], "-i")) {
|
|
||||||
strcpy(interface, argv[2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 判断运行用户禁止非root用户运行
|
|
||||||
if (geteuid() == 0) {
|
|
||||||
;
|
|
||||||
} else {
|
|
||||||
printf("This process is not running as root.\n");
|
|
||||||
printf("\n");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断网卡是否存在
|
|
||||||
char command_ifconfig[BUFFER + 20] = { 0 };
|
|
||||||
snprintf(command_ifconfig, BUFFER + 20, "ifconfig %s", interface);
|
|
||||||
// 判断必要命令是否存在
|
|
||||||
if (command_exists(command_ifconfig)) {
|
|
||||||
;
|
|
||||||
} else {
|
|
||||||
puts("The network card does not exist!");
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 后台运行
|
|
||||||
if (daemon(1, 1)) {
|
|
||||||
perror("daemon");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 进程优先级
|
|
||||||
if (-1 == (nice_(-20)))
|
|
||||||
perror("nice_");
|
|
||||||
|
|
||||||
// 哈希集合
|
|
||||||
if ((r = system("ipset create root hash:ip > /dev/null 2>&1")) != -1) {
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断必要命令是否存在
|
|
||||||
if (command_exists("which tcpdump")) {
|
|
||||||
;
|
|
||||||
} else {
|
|
||||||
r = system("yum -y install tcpdump > /dev/null 2>&1");
|
|
||||||
r = system("apt -y install tcpdump > /dev/null 2>&1");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 子进程
|
|
||||||
pid1 = fork(); // 创建子进程
|
|
||||||
if (pid1 == 0) {
|
|
||||||
while (1) {
|
|
||||||
FILE *fp = popen("ipset list root | grep \"Number of entries\" | cut -d : -f 2 | xargs", "r");
|
|
||||||
char line[BUFFER] = { 0 };
|
|
||||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
|
||||||
line[strcspn(line, "\n")] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (atoi(line) >= MAXIPSET) {
|
|
||||||
r = system("ipset flush root");
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("%s\n", line);
|
|
||||||
pclose(fp);
|
|
||||||
sleep(3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 子进程
|
|
||||||
pid2 = fork(); // 创建子进程
|
|
||||||
if (pid2 == 0) {
|
|
||||||
// 缓冲区用于存储每行的输出
|
|
||||||
char line[BUFFER];
|
|
||||||
// 要执行的命令
|
|
||||||
char command_tcpdump[BUFFER + 256] = { 0 };
|
|
||||||
snprintf(command_tcpdump, BUFFER + 256, "tcpdump -i %s -n 'tcp' | awk '{print $3}' | cut -d '.' -f 1-4", interface);
|
|
||||||
|
|
||||||
// 地域白名单
|
|
||||||
char _region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
|
|
||||||
char qqwry_region_list[WHITELIST_IP_NUM][WHITELIST_IP_NUM] = { { 0 }, { 0 } };
|
|
||||||
char _REGION_LIST_COPY[BUFFER] = { 0 };
|
|
||||||
char QQWRY_REGION_LIST_COPY[BUFFER] = { 0 };
|
|
||||||
|
|
||||||
if (access(xdb_path, F_OK) == -1) { // 判断 ip2region 地址定位库是否存在
|
|
||||||
xdb_path = "ip2region/ip2region.xdb";
|
|
||||||
if (access(xdb_path, F_OK) == -1) {
|
|
||||||
printf("ip2region.xdb DOESN'T EXIST!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开管道来执行命令
|
|
||||||
FILE *fp = popen(command_tcpdump, "r");
|
|
||||||
if (fp == NULL) {
|
|
||||||
perror("popen failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 逐行读取命令输出
|
|
||||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
|
||||||
line[strcspn(line, "\n")] = '\0';
|
|
||||||
|
|
||||||
if (is_valid_ip(line)) {
|
|
||||||
|
|
||||||
char *qqwry_region = qqwry_(line);
|
|
||||||
if (qqwry_region == NULL) {
|
|
||||||
printf("qqwry 解析地域错误\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *area = ip2region(xdb_path, line);
|
|
||||||
if (area == NULL) {
|
|
||||||
printf("ip2region 解析地域错误\n");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 取环境变量
|
|
||||||
const char *REGION_ENV = getenv("REGION");
|
|
||||||
if (REGION_ENV != NULL) {
|
|
||||||
printf("REGION: %s\n", REGION_ENV);
|
|
||||||
strcpy(_REGION_LIST_COPY, REGION_ENV);
|
|
||||||
strcpy(QQWRY_REGION_LIST_COPY, REGION_ENV);
|
|
||||||
} else {
|
|
||||||
strcpy(_REGION_LIST_COPY, "局域网 内网 中国 ");
|
|
||||||
strcpy(QQWRY_REGION_LIST_COPY, "局域网 内网 中国 ");
|
|
||||||
}
|
|
||||||
//printf("REGION_LIST : %s\n", _REGION_LIST_COPY);
|
|
||||||
|
|
||||||
split_string(QQWRY_REGION_LIST_COPY, " ", qqwry_region_list); // 分割后存储在 qqwry_region_list
|
|
||||||
if (isregion(qqwry_region, qqwry_region_list) == 1) { // 返回1表示在白名单列表
|
|
||||||
;
|
|
||||||
} else {
|
|
||||||
split_string(_REGION_LIST_COPY, " ", _region_list);
|
|
||||||
if (isregion(area, _region_list) == 1) { // 返回1表示在白名单列表
|
|
||||||
;
|
|
||||||
} else {
|
|
||||||
char ipquery_command[BUFFER + 100] = { 0 };
|
|
||||||
snprintf(ipquery_command, BUFFER + 100, "./IP_region_query/ipquery %s", line);
|
|
||||||
FILE *fp = popen(ipquery_command, "r");
|
|
||||||
if (fp == NULL) {
|
|
||||||
perror("popen failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建足够大的缓冲区来存储命令输出
|
|
||||||
char buffer[1024 * 2]; // 2KB 缓冲区
|
|
||||||
size_t bytesRead = fread(buffer, 1, sizeof(buffer) - 1, fp);
|
|
||||||
buffer[bytesRead] = '\0';
|
|
||||||
|
|
||||||
pclose(fp);
|
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
char *p = strstr(buffer, "中国");
|
|
||||||
if (p == NULL) {
|
|
||||||
printf("%s %s", line, buffer);
|
|
||||||
|
|
||||||
char command_ipset[BUFFER + 256] = { 0 };
|
|
||||||
snprintf(command_ipset, sizeof(command_ipset), "ipset add root %s > /dev/null 2>&1", line);
|
|
||||||
int r = system(command_ipset);
|
|
||||||
if (r == -1) {
|
|
||||||
perror("system command failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(qqwry_region);
|
|
||||||
free(area);
|
|
||||||
|
|
||||||
} else { // 是正确IP
|
|
||||||
printf("%s is not a valid IPv4 address.\n", line);
|
|
||||||
}
|
|
||||||
} // while
|
|
||||||
|
|
||||||
// 关闭管道
|
|
||||||
pclose(fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// 父进程 主进程循环,检查子进程运行情况
|
|
||||||
int iteration = 0;
|
|
||||||
while (1) {
|
|
||||||
iteration++;
|
|
||||||
|
|
||||||
if (iteration >= 3600*3) {
|
|
||||||
iteration = 0;
|
|
||||||
printf("准备重启进程...\n");
|
|
||||||
restart_process(pid1, pid2, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
sleep(1); // 每次检查间隔1秒
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
26
main.h
26
main.h
@@ -1,26 +0,0 @@
|
|||||||
#ifndef MAIN_H
|
|
||||||
#define MAIN_h
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <sys/resource.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
|
|
||||||
#include "ip2region.h"
|
|
||||||
#include "qqwry.h"
|
|
||||||
#include "common.h"
|
|
||||||
|
|
||||||
#define RED "\033[31m"
|
|
||||||
#define RESET "\033[0m"
|
|
||||||
#define WHITELIST_IP_NUM 1024
|
|
||||||
#define MAXIPSET 65534
|
|
||||||
|
|
||||||
char *xdb_path = "ip2region.xdb";
|
|
||||||
pid_t pid1, pid2; // 保存子进程的 PID
|
|
||||||
|
|
||||||
#endif
|
|
||||||
381
qqwry/qqwry.c
381
qqwry/qqwry.c
@@ -1,381 +0,0 @@
|
|||||||
|
|
||||||
#include "qqwry.h"
|
|
||||||
|
|
||||||
ip_data ip_defaults = {.parent_data = NULL,.child_data = NULL,.index_size = 7,.isp = 1 };
|
|
||||||
|
|
||||||
int qqwry_init(char *file)
|
|
||||||
{
|
|
||||||
int buff;
|
|
||||||
|
|
||||||
ip_defaults.fp = fopen(file, "r");
|
|
||||||
if (ip_defaults.fp == NULL) {
|
|
||||||
fprintf(stderr, "failed to open %s\n", file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
readvalue(4, &buff); //first 4 bytes represents the offset of first index
|
|
||||||
ip_defaults.first_item = buff;
|
|
||||||
readvalue(4, &buff);
|
|
||||||
ip_defaults.last_item = buff;
|
|
||||||
ip_defaults.item_number = (ip_defaults.last_item - ip_defaults.first_item) / ip_defaults.index_size;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int qqwry_match(char *pattern, char *subject)
|
|
||||||
{
|
|
||||||
regex_t regex;
|
|
||||||
int reti, ret;
|
|
||||||
char msgbuf[100];
|
|
||||||
|
|
||||||
/* Compile regular expression */
|
|
||||||
reti = regcomp(®ex, pattern, 0);
|
|
||||||
if (reti) {
|
|
||||||
fprintf(stderr, "Could not compile regex\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Execute regular expression */
|
|
||||||
reti = regexec(®ex, subject, 0, NULL, 0);
|
|
||||||
if (!reti) {
|
|
||||||
ret = 1;
|
|
||||||
} else if (reti == REG_NOMATCH) {
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
|
||||||
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free memory allocated to the pattern buffer by regcomp() */
|
|
||||||
regfree(®ex);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
iconv_t initialize_iconv(const char *target, const char *src) {
|
|
||||||
// 创建转换描述符
|
|
||||||
iconv_t iconvDesc = iconv_open(target, src);
|
|
||||||
|
|
||||||
// 检查 iconv_open 是否成功
|
|
||||||
if (iconvDesc == (iconv_t) - 1) {
|
|
||||||
// 如果失败,打印错误信息并返回 NULL
|
|
||||||
fprintf(stderr, "Error: Conversion from '%s' to '%s' is not available.\n", src, target);
|
|
||||||
return (iconv_t)NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 成功时返回 iconv_t 描述符
|
|
||||||
return iconvDesc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gbk2utf8(char *utf8_str, char *gbk_str)
|
|
||||||
{
|
|
||||||
iconv_t iconvDesc = initialize_iconv("UTF-8//TRANSLIT//IGNORE", "GBK");
|
|
||||||
size_t iconv_value, len, utf8len;
|
|
||||||
//int len_start;
|
|
||||||
|
|
||||||
len = strlen(gbk_str) + 1;
|
|
||||||
if (!len) {
|
|
||||||
fprintf(stderr, "iconvISO2UTF8: input String is empty.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Assign enough space to put the UTF-8. */
|
|
||||||
utf8len = 3 * len;
|
|
||||||
if (!utf8_str) {
|
|
||||||
fprintf(stderr, "iconvISO2UTF8: Calloc failed.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
iconv_value = iconv(iconvDesc, &gbk_str, &len, &utf8_str, &utf8len);
|
|
||||||
/* Handle failures. */
|
|
||||||
if (iconv_value == (size_t)-1) {
|
|
||||||
switch (errno) {
|
|
||||||
/* See "man 3 iconv" for an explanation. */
|
|
||||||
case EILSEQ:
|
|
||||||
fprintf(stderr, "iconv failed: Invalid multibyte sequence, in string '%s', length %d, out string '%s', length %d\n", gbk_str, (int)len, utf8_str, (int)utf8len);
|
|
||||||
break;
|
|
||||||
case EINVAL:
|
|
||||||
fprintf(stderr, "iconv failed: Incomplete multibyte sequence, in string '%s', length %d, out string '%s', length %d\n", gbk_str, (int)len, utf8_str, (int)utf8len);
|
|
||||||
break;
|
|
||||||
case E2BIG:
|
|
||||||
fprintf(stderr, "iconv failed: No more room, in string '%s', length %d, out string '%s', length %d\n", gbk_str, (int)len, utf8_str, (int)utf8len);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "iconv failed, in string '%s', length %d, out string '%s', length %d\n", gbk_str, (int)len, utf8_str, (int)utf8len);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iconv_close(iconvDesc) != 0) {
|
|
||||||
fprintf(stderr, "libicon close failed: %s", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return utf8len;
|
|
||||||
}
|
|
||||||
|
|
||||||
int readbyte(int size, int offset, int *buff)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
int nbytes = 1;
|
|
||||||
*buff = 0;
|
|
||||||
if (ip_defaults.fp != NULL) {
|
|
||||||
//if offset is negative,keep the current offset unchanged
|
|
||||||
if (offset >= 0) {
|
|
||||||
qqwry_seek(offset);
|
|
||||||
} else {
|
|
||||||
int curr_pos = ftell(ip_defaults.fp);
|
|
||||||
fseek(ip_defaults.fp, curr_pos, SEEK_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((count = fread(buff, nbytes, size, ip_defaults.fp)) != size) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int readvalue(unsigned int size, int *buff)
|
|
||||||
{
|
|
||||||
return readbyte(size, -1, buff);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_ip_range(unsigned int offset)
|
|
||||||
{
|
|
||||||
readbyte(4, offset, (int *)(&ip_defaults.startip));
|
|
||||||
//skip 3 bytes to read the next ip
|
|
||||||
qqwry_forward(3);
|
|
||||||
readvalue(4, (int *)(&ip_defaults.endip));
|
|
||||||
}
|
|
||||||
|
|
||||||
void qqwry_seek(int offset)
|
|
||||||
{
|
|
||||||
fseek(ip_defaults.fp, offset, SEEK_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
void qqwry_forward(unsigned int byte)
|
|
||||||
{
|
|
||||||
fseek(ip_defaults.fp, byte, SEEK_CUR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void qqwry_back(unsigned int byte)
|
|
||||||
{
|
|
||||||
int currPos = ftell(ip_defaults.fp);
|
|
||||||
qqwry_seek(currPos - byte);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
char *long2ip(int ip) {
|
|
||||||
// 分配16字节内存用于存储IP字符串
|
|
||||||
char *ip_str = malloc(16 * sizeof(char));
|
|
||||||
|
|
||||||
if (ip_str == NULL) {
|
|
||||||
// 如果内存分配失败,返回NULL
|
|
||||||
fprintf(stderr, "Memory allocation failed\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 将IP转换为字符串
|
|
||||||
snprintf(ip_str, 16, "%d.%d.%d.%d",
|
|
||||||
(ip >> 24) & 0xFF,
|
|
||||||
(ip >> 16) & 0xFF,
|
|
||||||
(ip >> 8) & 0xFF,
|
|
||||||
ip & 0xFF);
|
|
||||||
|
|
||||||
return ip_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ip2long(char *ip)
|
|
||||||
{
|
|
||||||
int nip = 0, tmp = 0, step = 24;
|
|
||||||
char *copy = strdup(ip);
|
|
||||||
char *token = strtok(copy, ".");
|
|
||||||
|
|
||||||
while (token) {
|
|
||||||
tmp = (unsigned int)atoi(token);
|
|
||||||
tmp <<= step;
|
|
||||||
nip += tmp;
|
|
||||||
step -= 8;
|
|
||||||
token = strtok(NULL, ".");
|
|
||||||
}
|
|
||||||
free(copy);
|
|
||||||
return nip;
|
|
||||||
}
|
|
||||||
|
|
||||||
int search_record(char *ip)
|
|
||||||
{
|
|
||||||
int numeric_ip = ip2long(ip);
|
|
||||||
int low = 0;
|
|
||||||
int high = ip_defaults.item_number;
|
|
||||||
return binary_search(low, high, numeric_ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
int binary_search(int low, int high, int ip)
|
|
||||||
{
|
|
||||||
unsigned int mid, offset, startip, endip;
|
|
||||||
|
|
||||||
if (low <= high) {
|
|
||||||
mid = low + (high - low) / 2;
|
|
||||||
offset = round(ip_defaults.first_item + mid * ip_defaults.index_size);
|
|
||||||
set_ip_range(offset);
|
|
||||||
startip = ip_defaults.startip;
|
|
||||||
endip = ip_defaults.endip;
|
|
||||||
if (ip >= startip && ip <= endip) {
|
|
||||||
return offset;
|
|
||||||
}
|
|
||||||
//if ip is below the lower limit, decrease the upper limit
|
|
||||||
if (ip < startip) {
|
|
||||||
return binary_search(low, mid - 1, ip);
|
|
||||||
}
|
|
||||||
//if ip is above the lower limit, increase the lower limit
|
|
||||||
return binary_search(mid + 1, high, ip);
|
|
||||||
}
|
|
||||||
return ip_defaults.last_item;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *get_string()
|
|
||||||
{
|
|
||||||
unsigned int buff = 0;
|
|
||||||
char *str = realloc(NULL, sizeof(char));
|
|
||||||
char *tmp;
|
|
||||||
int i = 0, c = 0;
|
|
||||||
|
|
||||||
if ((c = readvalue(1, (int *)(&buff))) != 1) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; buff != 0; i++) {
|
|
||||||
str[i] = buff;
|
|
||||||
tmp = realloc(str, (sizeof(char)) * (i + 2));
|
|
||||||
str = tmp;
|
|
||||||
readvalue(1, (int *)(&buff));
|
|
||||||
}
|
|
||||||
str[i] = '\0';
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *get_child_data()
|
|
||||||
{
|
|
||||||
unsigned int flag, offset;
|
|
||||||
readvalue(1, (int *)(&flag));
|
|
||||||
if (flag == 0) { //no child data
|
|
||||||
return 0;
|
|
||||||
} else if (flag == 1 || flag == 2) { // redirection for child data
|
|
||||||
readvalue(3, (int *)(&offset));
|
|
||||||
qqwry_seek(offset);
|
|
||||||
return get_string();
|
|
||||||
}
|
|
||||||
// no redirection for child data
|
|
||||||
qqwry_back(1);
|
|
||||||
return get_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
int convert_data(char *parent_data, char *child_data)
|
|
||||||
{
|
|
||||||
ip_defaults.parent_data = malloc(strlen(parent_data) * 3); //in utf8,one chinese character could consume up to 3 bytes
|
|
||||||
gbk2utf8(ip_defaults.parent_data, parent_data);
|
|
||||||
ip_defaults.child_data = malloc(strlen(child_data) * 3);
|
|
||||||
gbk2utf8(ip_defaults.child_data, child_data);
|
|
||||||
|
|
||||||
if (qqwry_match("移动", ip_defaults.child_data)) {
|
|
||||||
ip_defaults.isp = 0x03;
|
|
||||||
} else if (qqwry_match("联通", ip_defaults.child_data)) {
|
|
||||||
ip_defaults.isp = 0x02;
|
|
||||||
} else {
|
|
||||||
ip_defaults.isp = 0x01;
|
|
||||||
}
|
|
||||||
free(parent_data);
|
|
||||||
free(child_data);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int qqwry_redirect(int bytes)
|
|
||||||
{
|
|
||||||
int redirect_offset;
|
|
||||||
readvalue(bytes, &redirect_offset);
|
|
||||||
qqwry_seek(redirect_offset);
|
|
||||||
return redirect_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_data(int offset)
|
|
||||||
{ //get record data
|
|
||||||
int flag, redirect_offset;
|
|
||||||
char *parent_data, *child_data;
|
|
||||||
readbyte(1, offset + 4, &flag); //get the flag value to see if the data is stored elsewhere
|
|
||||||
|
|
||||||
if (flag == 1) { //this means we should look elsewhere for both
|
|
||||||
redirect_offset = qqwry_redirect(3); //read 3 bytes to get a new offset and redirect there
|
|
||||||
readvalue(1, &flag);
|
|
||||||
if (flag == 2) {
|
|
||||||
// child data is elsewhere
|
|
||||||
qqwry_redirect(3);
|
|
||||||
parent_data = get_string();
|
|
||||||
qqwry_seek(redirect_offset + 4);
|
|
||||||
child_data = get_child_data();
|
|
||||||
} else { // no redirection for parent data
|
|
||||||
qqwry_back(1);
|
|
||||||
parent_data = get_string();
|
|
||||||
child_data = get_child_data();
|
|
||||||
}
|
|
||||||
} else if (flag == 2) { //redirection for only parent
|
|
||||||
qqwry_redirect(3);
|
|
||||||
parent_data = get_string();
|
|
||||||
qqwry_seek(offset + 8);
|
|
||||||
child_data = get_child_data();
|
|
||||||
} else { // no redirection for both parent and child
|
|
||||||
qqwry_back(1);
|
|
||||||
parent_data = get_string();
|
|
||||||
child_data = get_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
convert_data(parent_data, child_data);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_location(char *ip)
|
|
||||||
{
|
|
||||||
//offset is the address where the ip is found. first 4 bytes is the start ip address of the ip range and the following 3 bytes is the offset pointing to the actual record data;
|
|
||||||
unsigned int offset = search_record(ip);
|
|
||||||
unsigned int tmp_offset;
|
|
||||||
qqwry_seek(offset + 4); // skip 4 byte to get the offset value pointing to record data
|
|
||||||
readvalue(3, (int *)(&tmp_offset)); // the offset pointing to the data
|
|
||||||
get_data(tmp_offset);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *qqwry_(char *ip)
|
|
||||||
{
|
|
||||||
char *qqdb_path = "qqwry.dat";
|
|
||||||
if (access(qqdb_path, F_OK) == -1) { // 判断 ip2region 地址定位库是否存在
|
|
||||||
qqdb_path = "qqwry/qqwry.dat";
|
|
||||||
if (access(qqdb_path, F_OK) == -1) {
|
|
||||||
printf("qqwry.dat DOESN'T EXIST!\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
qqwry_init(qqdb_path);
|
|
||||||
|
|
||||||
|
|
||||||
get_location(ip);
|
|
||||||
//printf("%s-%s %d\n", ip_defaults.parent_data, ip_defaults.child_data, ip_defaults.isp);
|
|
||||||
//printf("QQWRY %s %s-%s\n", ip, ip_defaults.parent_data, ip_defaults.child_data);
|
|
||||||
|
|
||||||
// 计算拼接后的字符串所需的长度
|
|
||||||
size_t len = strlen(ip_defaults.parent_data) + strlen(ip_defaults.child_data) + 2; // +2 for the hyphen and null terminator
|
|
||||||
char *result = malloc(len);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
// 拼接字符串,格式为 "parent_data-child_data"
|
|
||||||
snprintf(result, len, "%s-%s", ip_defaults.parent_data, ip_defaults.child_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(ip_defaults.parent_data);
|
|
||||||
free(ip_defaults.child_data);
|
|
||||||
fclose(ip_defaults.fp);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
BIN
qqwry/qqwry.dat
BIN
qqwry/qqwry.dat
Binary file not shown.
@@ -1,31 +0,0 @@
|
|||||||
#include <unistd.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <iconv.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <regex.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FILE *fp;
|
|
||||||
unsigned int index_size;
|
|
||||||
unsigned int first_item, last_item;
|
|
||||||
unsigned int item_number, startip, endip, curr_data_offset;
|
|
||||||
char *parent_data, *child_data;
|
|
||||||
int isp;
|
|
||||||
} ip_data;
|
|
||||||
|
|
||||||
int search_record(char *ip);
|
|
||||||
int binary_search(int low, int high, int ip);
|
|
||||||
int readbyte(int size, int offset, int *buff);
|
|
||||||
int readvalue(unsigned int size, int *buff);
|
|
||||||
void qqwry_seek(int offset);
|
|
||||||
void qqwry_forward(unsigned int byte);
|
|
||||||
void qqwry_back(unsigned int byte);
|
|
||||||
int get_location(char *ip);
|
|
||||||
int gbk2utf8(char *utf8_str, char *gbk_str);
|
|
||||||
|
|
||||||
extern char *qqwry_(char *ip);
|
|
||||||
BIN
qqwry/qqwry.o
BIN
qqwry/qqwry.o
Binary file not shown.
Reference in New Issue
Block a user