├── .gitattributes ├── .gitignore ├── AUTHORS ├── COPYING ├── FORMATS ├── Makefile.am ├── Makefile.dist ├── NEWS ├── README ├── README.graphcairo ├── SECURITY ├── TODO ├── asn.c ├── asn.h ├── bootstrap.sh ├── configure.ac ├── curses.c ├── display.c ├── display.h ├── dns.c ├── dns.h ├── getopt ├── getopt.c ├── getopt.h └── getopt1.c ├── graphcairo ├── graphcairo-backend.h ├── graphcairo-mtr.c ├── graphcairo-mtr.h ├── graphcairo-xcb.c ├── graphcairo-xcb.h ├── graphcairo-xlib.c ├── graphcairo.c └── graphcairo.h ├── gtk.c ├── img ├── Makefile.am └── mtr_icon.xpm ├── mtr-curses.h ├── mtr-gtk.h ├── mtr.8 ├── mtr.c ├── mtr.h ├── net.c ├── net.h ├── raw.c ├── raw.h ├── report.c ├── report.h ├── select.c ├── select.h ├── split.c ├── split.h └── version.h.in /.gitattributes: -------------------------------------------------------------------------------- 1 | README.md export-ignore 2 | img/gc-screenshot*.png export-ignore 3 | img/ii-screenshot*.png export-ignore 4 | img/ch-screenshot*.png export-ignore 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | *.o 3 | 4 | Makefile 5 | Makefile.in 6 | aclocal.m4 7 | confdefs.h 8 | config.* 9 | configure 10 | confinc 11 | confmf 12 | conftest.* 13 | depcomp 14 | compile 15 | install-sh 16 | missing 17 | stamp-h1* 18 | 19 | /autom4te.cache/ 20 | **/.deps/ 21 | **/.dirstamp 22 | /ChangeLog 23 | /INSTALL 24 | /mtr 25 | /version.h 26 | /version.h.tmp 27 | 28 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | Matt Kimball is the primary author of mtr. 3 | 4 | Roger Wolff is currently maintaing mtr. 5 | 6 | 7 | Bug reports and feature requests should be sent to the mtr 8 | mailing list. See the README file for details. 9 | 10 | Thanks to everyone who has provided feedback on mtr. 11 | 12 | Thanks especially to those of you who have sent code: 13 | (Reverse alphabetical order, and sometimes I just add people at 14 | the end... ) 15 | 16 | Bohdan Vlasyuk 17 | Evgeniy Tretyak 18 | John Thacker 19 | Juha Takala 20 | David Sward 21 | David Stone 22 | Andrew Stesin 23 | Greg Stark 24 | Robert Sparks 25 | Mike Simons 26 | Aaron Scarisbrick 27 | Craig Milo Rogers 28 | Antonio Querubin 29 | Russell Nelson 30 | Davin Milun 31 | Josh Martin 32 | Alexander V. Lukyanov 33 | Charles Levert 34 | Bertrand Leconte 35 | Anand Kumria 36 | Olav Kvittem 37 | Adam Kramer 38 | Philip Kizer 39 | Simon Kirby 40 | Christophe Kalt 41 | Steve Kann 42 | Brett Johnson 43 | Roland Illig 44 | Damian Gryski 45 | Rob Foehl 46 | Mircea Damian 47 | Cougar 48 | Travis Cross 49 | Brian Casey 50 | Andrew Brown 51 | Bill Bogstad 52 | Marc Bejarano 53 | Moritz Barsnick 54 | Thomas Klausner 55 | Roderick Groesbeek 56 | Kyle J. McKay 57 | Joseph Carter 58 | Thales 59 | "Min" 60 | Vaibhav Bajpai 61 | Jürgen Schönwälder 62 | 63 | and anyone who has slipped through the cracks of my mail file. 64 | 65 | Authors: If you want your Email mentioned here, send it to me. 66 | If you don't want your Email mentioned here, tell me. 67 | 68 | -- REW 69 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /FORMATS: -------------------------------------------------------------------------------- 1 | 2 | The "split" format is for a separating the gui from the main program. 3 | The main program can be installed setuid, and you don't want to link a 4 | gui-library with a setuid program. 5 | 6 | 7 | The split format is: 8 | 9 | 10 | 11 | 12 | The "raw" format is: 13 | 14 | hostline|pingline|dnsline|timestampline 15 | 16 | hostline: 17 | h 18 | 19 | pingline: 20 | p 21 | 22 | dnsline: 23 | d 24 | 25 | timestampline: 26 | t 27 | 28 | 29 | Timestampline is not yet implemented. Need to find out how to do 30 | ICMP timestamping first. :-) 31 | 32 | 33 | Someone suggested to put the following text here. As to context: Some 34 | people are wondering why mtr sometimes reports hosts beyond the 35 | destination host. 36 | 37 | 38 | The FINAL host will occasionally be mentioned at position n, n+1, n+2 39 | etc. 40 | 41 | You know traceroute, right? It sends a packet, waits for the reply to 42 | come back and when it comes back, it sends the next packet. 43 | 44 | If say hosts 5-8 do not send "time exceeded" packets, you'll wait a 45 | 4*3 = twelve seconds extra before you get any results on hosts 9 and 46 | further. MTR doesn't work like that. 47 | 48 | In theory we could send out a probe for host 1-40 all at once. But 49 | this would pose an unnecessary burden on the network. So what we do, 50 | is we send out probes for a max of 5 hosts beyond where we've seen a 51 | reply. So in the example above, we'd see a reply from router at 52 | position 4, then we'd send out 5-9 (and because the max-host is now at 53 | 9, we'll send them out at 1s/9 = 111ms intervals). When the reply from 54 | host 9 comes back, we'll start probing for host 10-15 (at about 60ms 55 | intervals). But suppose the network delay upto host 9 is already 200ms 56 | and suppose our destination host is at position 11. Then by the time 57 | the packet from host 11 comes back, we'll already have sent probe 58 | packets for position 12, 13, and 14! Those will come back as 59 | "destination reached" and be reported by the "raw" mode. 60 | 61 | Curses mode will stop showing hosts with position numbers beyond the 62 | first reply of the destination host. It could gather the information 63 | about replies to packets sent as probes FURTHER than it actually is 64 | into the line displayed at its true position, but it doesn't (yet). 65 | 66 | In fact the above example is almost completely true: 67 | 68 | % mtr -r -n -c 2 152.179.99.218 | tail -5 69 | 13.|-- 144.232.18.238 0.0% 2 94.8 95.4 94.8 96.0 0.8 70 | 14.|-- 152.63.16.182 0.0% 2 95.1 95.5 95.1 95.8 0.5 71 | 15.|-- 152.63.64.106 0.0% 2 163.9 163.9 163.9 164.0 0.1 72 | 16.|-- 152.63.50.89 50.0% 2 163.7 163.7 163.7 163.7 0.0 73 | 17.|-- 152.179.99.218 50.0% 2 168.2 168.2 168.2 168.2 0.0 74 | % mtr -l -c 2 152.179.99.218 | grep -v "^[dp]" |tail -7 75 | h 10 144.232.1.41 76 | h 11 144.232.4.96 77 | h 16 152.179.99.218 78 | h 17 152.179.99.218 79 | h 18 152.179.99.218 80 | h 12 144.232.18.238 81 | h 13 152.63.16.182 82 | 83 | As you can see we get the reply from the destination host at position 84 | 16 AFTER we've sent probes for position 17 and 18. When those come 85 | back, they are reported. That's what raw mode does. It reports the raw 86 | information. 87 | 88 | If you write a backend for the raw mode, it's up to you to 89 | filter/display the results. 90 | 91 | h 10 144.232.1.41 92 | h 11 144.232.4.96 93 | h 12 144.232.18.238 94 | h 13 152.63.16.182 95 | h 14 152.63.64.106 96 | h 15 152.63.50.89 97 | h 16 152.179.99.218 98 | h 17 152.179.99.218 99 | h 18 152.179.99.218 100 | 101 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = img 2 | 3 | sbin_PROGRAMS = mtr 4 | man_MANS = mtr.8 5 | install-exec-hook: 6 | chmod u+s $(DESTDIR)$(sbindir)/mtr 7 | 8 | mtr_SOURCES = mtr.c \ 9 | net.c net.h \ 10 | dns.c dns.h \ 11 | raw.c raw.h \ 12 | split.c split.h \ 13 | display.c display.h \ 14 | report.c report.h \ 15 | select.c select.h \ 16 | mtr-curses.h \ 17 | mtr-gtk.h 18 | 19 | nodist_mtr_SOURCES = version.h 20 | EXTRA_mtr_SOURCES = curses.c \ 21 | gtk.c 22 | AM_CPPFLAGS = 23 | mtr_DEPENDENCIES = $(GTK_OBJ) $(CURSES_OBJ) 24 | mtr_LDFLAGS = $(GTK_OBJ) $(CURSES_OBJ) 25 | mtr_LDADD = $(RESOLV_LIBS) 26 | 27 | if LOCAL_GETOPT 28 | mtr_SOURCES += getopt/getopt.c getopt/getopt1.c getopt/getopt.h 29 | AM_CPPFLAGS += -Igetopt 30 | endif 31 | 32 | if IPINFO 33 | mtr_SOURCES += asn.c asn.h 34 | endif 35 | 36 | if GRAPHCAIRO 37 | mtr_LDADD += libgraphcairo.a 38 | noinst_LIBRARIES = libgraphcairo.a 39 | libgraphcairo_a_SOURCES = \ 40 | graphcairo/graphcairo.c graphcairo/graphcairo.h \ 41 | graphcairo/graphcairo-mtr.c graphcairo/graphcairo-mtr.h \ 42 | graphcairo/graphcairo-backend.h 43 | if GRAPHCAIRO_XCB 44 | libgraphcairo_a_SOURCES += graphcairo/graphcairo-xcb.c 45 | endif 46 | if GRAPHCAIRO_XLIB 47 | libgraphcairo_a_SOURCES += graphcairo/graphcairo-xlib.c 48 | endif 49 | libgraphcairo_a_CPPFLAGS = @graphcairo_CFLAGS@ -Igraphcairo 50 | AM_CPPFLAGS += -Igraphcairo 51 | mtr_LDADD += @graphcairo_LIBS@ 52 | mtr_SOURCES += $(graphcairo_a_SOURCES) 53 | endif 54 | 55 | if LIBIDN 56 | AM_CPPFLAGS += @libidn_CFLAGS@ 57 | mtr_LDADD += @libidn_LIBS@ 58 | endif 59 | 60 | CLEANFILES = version.h 61 | BUILT_SOURCES = version.h 62 | 63 | version.h: version.h.tmp Makefile $(mtr_SOURCES) 64 | @cat version.h.tmp > $@; \ 65 | if [ -d .git ] && [ -n "$$(which git)" ]; then \ 66 | xver="+git:$$(git rev-list -n1 --abbrev=8 --abbrev-commit HEAD)"; \ 67 | sed \ 68 | -e "/#define *MTR_VERSION */{s/\"\([^\"]*\)\"/\"\1$$xver\"/;}" \ 69 | version.h.tmp > $@; \ 70 | fi; 71 | 72 | EXTRA_DIST = SECURITY mtr.8 Makefile Makefile.dist 73 | distclean-local: 74 | (sleep 3; cp Makefile.dist Makefile) & 75 | rm -f *.orig 76 | 77 | DISTCLEANFILES = *~ 78 | 79 | -------------------------------------------------------------------------------- /Makefile.dist: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # This is an attempt on simplifying the compilation of mtr to a simple "make". 4 | # 5 | 6 | firstrule: 7 | ./configure 8 | $(MAKE) 9 | 10 | clean: 11 | rm -f *.o *~ core 12 | 13 | distclean: clean 14 | rm -f mtr config.cache config.status config.log \ 15 | stamp-h stamp-h[0-9]* TAGS ID 16 | 17 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | WHAT'S NEW? 2 | 3 | V0.86 Fixed default hostname logic. 4 | Fix for NetBSD: 64bit time_t -- Thomas Klausner 5 | Fix unnecessary runtime dependency on glib from VSYakovetsky through 6 | Thomas 7 | Inverted IPINFO define in the code. Removes double negatives. 8 | -- Vladimir Yakovetsky, REW. 9 | Fixed failure on IPv4 only systems when IPv6 was available at 10 | compile time. -- REW. 11 | Fixed (longstanding) bug that mtr used 100% cpu when paused. 12 | Cosmetic changes from Richard Hartman. 13 | 14 | V0.85 Fixed asn support. (better compile time detection of required features) 15 | support for multiple hostnames. (fixed in 0.86) 16 | 17 | V0.84 Fix some glib things by Thomas. 18 | 19 | V0.83 Move to github. Mostly done by Travis. 20 | 21 | Author: Travis Cross 22 | Add autotools bootstrap script 23 | Update README for building from git repository 24 | Cleanup whitespace in the NEWS file 25 | Resolve -Wunused-but-set-variable warnings 26 | Resolve -Wnull-dereference clang warning 27 | Add -z / --show-ip support 28 | Author: R.E. Wolff (mostly from patches by others) 29 | some running patches 30 | Made report wide switch properly to displayreport mode. Bug #780647 31 | fixed gtk field order. Bug #701513 32 | added aslookup patch from bug #701514 33 | added some extra clarifications to the SECURITY file. 34 | enable ipv6 resolvers. By Antonio Querubin. Fixes bug #752583 35 | 36 | V0.82 Removed old Changelog file appended at the end as oldest 37 | changes. 38 | 2011-03-28 Mark Kamichoff 39 | Enable decoding of ICMP extensions for MPLS for curses and 40 | report interfaces. Use the -e flag or press 'e' to enable it. 41 | 42 | V0.81 Moved to git. Testing git... 43 | 44 | V0.80 Some compilation fixes for BSD by Jeremy Chadwick 45 | 46 | 47 | V0.78/0.79 some compilation fixes for BSD&others by 48 | Thomas Klausner 49 | 50 | V0.76 display load sharing hosts in --raw output. 51 | added about button in gui. 52 | 53 | v0.75 Feelgood patch to move sprintf to snprintf. People might think 54 | that sprintf might cause a buffer overflow. Now it's clean. 55 | cut-paste patches: you can now copy an intermediate host to the 56 | clipboard. 57 | 58 | v0.74 Martin Pels' patch to allow UDP probes. 59 | KES reported a build problem. Turns out I need to install gtk-1.2 60 | on my development sytem, otherwise my release script causes the 61 | build to break. 62 | changed some docs to advertise the new mailing list. 63 | added documentation for the Mac OS X compilation problem. 64 | added -Wno-pointer-sign to the compiler options. 65 | Nico Lichtmaier's cleanup-gtk patch. (now mtr uses a more modern 66 | dialect of gtk). 67 | 68 | v0.73 Some securty patches. Although MTR drops privileges as soon 69 | as possible after opening the sockets, it still had some 70 | sprintf calls, which have now been converted into snprintf. 71 | 72 | v0.72 Fix signed/unsigned bug in IPV6 part 73 | improved random packet size behaviour. --REW 74 | 75 | v0.71 Some IPV6 fixes, introduce packet size cmdline option. 76 | (was already present as a cmdline argument) 77 | 78 | v0.70 Antinio submitted a cumulative patch containing some 79 | nice improvements. He also submitted an automake patch 80 | that causes mtr to no longer compile on my system. I 81 | refuse to have mtr "in the dark" that I can't test-compile 82 | the dist. 83 | 84 | v0.69 make distclean should now also remove "rej" files. 85 | Antonio Querubin: update getopt.h . More cleanups using 86 | new infrastructure. 87 | rcw: Fixed IPV6 support: When compiled in an IPV6-supporting 88 | environment, but when the kernel doesn't support IPV6, mtr would 89 | fail to start. 90 | 91 | v0.68 included some old patches. 92 | included patch from Antonio Querubin for better IPV6 support 93 | restructured some more whitespace. 94 | added mtr.h where "global" things should go. Not finished 95 | moving things around, but now that the infrastructure is there, 96 | it should be easy. 97 | 98 | v0.67 Bad keyboarding by REW caused this one out the door. Sorry. 99 | No changes. 100 | 101 | v0.66 Through the Debian bugtracking system a bug report and 102 | fix was sent my way, that deals with stupid optmization 103 | trying to save some 768 bytes of memory, sacrificing "it 104 | works" on a different architecture... (default char signedness) 105 | 106 | v0.65 Dancer Vesperman noted that mtr no longer traces past 107 | a section of non-responding hosts. Apparently I added 108 | a line in net.c that didn't make sense in mtr-0.56. I 109 | can't find the reason for adding that line, so someone 110 | who thinks (s)he needs it, should holler. 111 | 112 | v0.64 Philippe suggests to do the time_t thingy before socket.h. 113 | Apparently, MAC OS X doesn't compile socket.h otherwise. 114 | 115 | v0.63 Suggestion by RCW: Add -lm at line 70 of Configure.in. 116 | On my system no ill effects ensued, so this version released 117 | so that he can test if it still works on his sytem. 118 | 119 | Let me add that it's stupid that I have to specify that this 120 | this program now requires Automake version 1.5 to build, where 121 | Automake was intended to make software independent of different 122 | versions of build software! 123 | 124 | For those concerned about the above statement: If you're just 125 | trying to compile and use MTR, there is no need for automake. 126 | Just when you're messing with the configure and build system of 127 | mtr is automake a tool you need. 128 | 129 | v0.62 Apparently someone changed gethostbyname into gethostbyname2 130 | in mtr.c in an attempt to add IPV6 support. For systems without 131 | ipv6 support, the old gethostbyname should be used! Linux 132 | has the call even if you don't enable IPV6. Thanks Gary (rsub) 133 | 134 | v0.61 Attempt to get/print the local IP address. Now shows as 135 | 0.0.0.0 :-( Hints and tips appreciated! -- REW 136 | Lots of blank space reformatting. 137 | moved the interface address setting to net.c (where it 138 | belongs). 139 | 140 | v0.60 John Thacker submitted a surprisingly simple patch to 141 | enable linking against GTK2. (up to 2.4.0) 142 | 143 | v0.59 Josh Martin suggested to add some bounds checking to 144 | the dynamic field code. This caused me to delve in, and 145 | rewrite some things. Now 50 lines of code less, but cleaner 146 | code. :-) 147 | 148 | v0.58 I don't remember. Fogot to update this. :-( Check the 149 | patch. 150 | 151 | v0.57 Lots of whitespace cleanups. And a DNS fix: Don't do DNS 152 | lookups in raw mode with -n specified. 153 | 154 | v0.56 Fixed compile warnings. Now compiles with -Wall. If your 155 | compiler finds things mine didn't feel free to shout. 156 | 157 | v0.55 Cleanup patch. I'm going to do some maintenance on MTR, 158 | but I want to be able to say: Can you see which version 159 | fixed/broke things for you, so you're going to see a 160 | bunch of new releases soon. 161 | 162 | v0.54 Added "scrolling" patch from Roland Illig, to allow 163 | scrolling in text mode. I've always wanted this...... 164 | 165 | v0.53 Added fix for raw mode. 166 | 167 | v0.52 Mostly cleanups from Brett Johnson on MacOS X. It may 168 | clean up some compilation problems on MacOS X as well. 169 | 170 | v0.51 Fixed the bug introduced by the previous select loop fix... 171 | Thanks Evgeniy 172 | 173 | v0.50 Make "interface address" option work. 174 | Changes to "select" loop to allow window resizes (select 175 | interruption) to work. Thanks Mike! 176 | 177 | v0.49 Fix compilation problems on several platforms. 178 | 179 | v0.48 Draw names in red (GTK) or bold (Curses) if host doesn't 180 | respond. 181 | 182 | v0.47 Fixed a (believed-) non-exploitable bufferoverflow. 183 | Thanks Damian. 184 | 185 | v0.46 Included patch to be able to specify outgoing interface 186 | address. 187 | 188 | v0.45 People are pressuring me to release new versions with their 189 | changes. That's fine. Now this version just adds dynamic 190 | switching between numeric / dns names, and some minor 191 | stuff I forgot. This release serves as a code-sync-release. 192 | new version with even more new stuff in about two weeks! 193 | I'm afraid I don't know how to fix the MaxOS-X compilation 194 | problems in the source. Help wanted... 195 | 196 | v0.44 David Stone adds the "last" column to the gtk version. 197 | 198 | v0.43 Compile fixes. 199 | 200 | v0.41 Added afr's patch to allow disabling of gtk without Robn's hack. 201 | Made report mode report the newly added extra resolution. 202 | 203 | v0.40 Fixed some problems with HPUX and SunOS. 204 | Included Olav Kvittem's patch to do packetsize option. 205 | Made the timekeeping in micro seconds. 206 | 207 | v0.39 Forgot the parentheses around the previous fix... :-( 208 | 209 | v0.38 fixed some dubious code in dns.c (noted by someone's lint) 210 | 211 | v0.37 Added Bill Bogstad's "show the local host & time" patch. 212 | Added R. Sparks' show-last-ping patch, submitted by Philip Kizer. 213 | 214 | v0.36 Added Craigs change-the-interval-on-the-fly patch. 215 | Added Moritz Barsnick's "do something sensible if host not found" 216 | patch. 217 | Some cleanup of both Craigs and Moritz' patches. 218 | 219 | v0.35 Added Craig Milo Rogers pause/resume for GTK patch. 220 | Added Craig Milo Rogers cleanup of "reset". (restart at the beginning) 221 | Net_open used to send a first packet. After that the display-driver 222 | got a chance to distort the timing by taking its time to 223 | initialize. 224 | 225 | v0.34 Added Matt's nifty "use the icmp unreachables to do the timing" patch. 226 | Added Steve Kann's pause/resume patch. 227 | 228 | v0.33 Fixed the Linux glibc resolver problems. 229 | Fixed the off-by-one problem with -c option. 230 | 231 | v0.32 Fixed the FreeBSD bug detection stuff. 232 | 233 | v0.31 Fixed a few documentation issues. -- Matt 234 | Changed the autoconf stuff to find the resolver library on 235 | Solaris. -- REW 236 | Cleaned up the autoconf.in file a bit. -- Matt. 237 | 238 | v0.30 Fixed a typo in the changelog (NEWS) entry for 0.27. :-) 239 | added use of "MTR_OPTIONS" environment variable for defaults. 240 | 241 | v0.29 Lots of stuff. 242 | Neato overview display by David Sward. 243 | FreeBSD does wrong in the kernel the same that Solaris/x86 (see 244 | note for 0.27 does right. It forces mtr to send bad packets.... 245 | Adjusted "not too much at once" algorithm. Now probing 246 | continues as long as not more than 5 hosts are unknown. 247 | Returning packets usually allow us to do the first sweep 248 | in one go. 249 | 250 | v0.28 DNS lookups are now suppressed if you don't want them. 251 | 252 | v0.27 253 | Fixed bug that showed up on Solaris/x86. 254 | GTK mainloop now runs as it's supposed to. 255 | 256 | v0.26 257 | Added "-n" flag for numeric output. 258 | fixed IP numbers displaying backwards. 259 | GTK mainloop now runs at 10 packets per second. 260 | - That's too much if there are only 3 hosts 261 | - that's too little if there are 20 hosts. 262 | -> Someone tell me how to change the "ping-timeout" 263 | callback time in gtk. Can't find it in the docs. 264 | The default for "hostname" is now "localhost" so that 265 | you can start mtr without any arguments and later 266 | fill in the host you want to trace to. 267 | 268 | v0.25 269 | Included two "raw" formats. One for separating GUI from 270 | the setuid program, and one suitable for later parsing and 271 | displaying. Volunteers wanted to separate the GTK 272 | backend. Thanks to Bertrand Leconte for contributing 273 | the format that's now called "split". 274 | 275 | v0.24 276 | Fixed number of probes. Accidentally was counted per 277 | packet sent instead of per round of packets. 278 | 279 | v0.23 280 | Fixed Sparc alignment problem with statmalloc 281 | 282 | v0.22 283 | Roger has take over maintenance. 284 | mtr now uses an "int" to pass options to the kernel. 285 | Makes things work on Solaris and *BSD I'm told. 286 | mtr doesn't fire off a flurry of packets when a new 287 | second comes around. Instead they are spaced evenly 288 | around the whole second. This allows people with a 289 | relatively slow first link to do meaningful measurements 290 | of whatever is behind that. 291 | 292 | v0.21 293 | mtr now drops root permissions after it acquires the raw 294 | sockets it needs. 295 | mtr should be a bit happier about building under SCO and 296 | Solaris. 297 | Fixed the problem with packets arriving after a reset. 298 | 299 | v0.20 300 | The build process for mtr now uses automake. 301 | Fixed a build problem for Irix. 302 | Now uses non-blocking DNS code, so mtr can attempt 303 | to do reverse lookup on multiple hosts at once. 304 | Fewer packets are sent out each cycle, so mtr 305 | doesn't hog quite so much bandwidth. 306 | 307 | v0.19 308 | Fixed a type-o in curses.c 309 | 310 | v0.18 311 | Fixed the network code to work properly under FreeBSD. 312 | Hopefully this will fix some other operating systems too. 313 | Also, fixed a build problem and the DNS hanging bug. 314 | 315 | v0.17 316 | Fixed the configure script to always like with the math 317 | library. Added an icon. 318 | 319 | v0.16 320 | Added one #include to select.c. Some people were unable 321 | to build mtr without this line. 322 | 323 | v0.15 324 | Both the build process and the networking code have 325 | been cleaned up and reorganized. mtr now builds 326 | cleanly with GTK+ 0.99.8. 327 | 328 | --- Below is the contents of the old "Changelog file" that annoyed some 329 | people as it didn't contain any recent changes/news. 330 | 331 | 2002-03-06 Cougar 332 | + If hop doesn't respond, draw its name in red (GTK) or bold (curses) 333 | 334 | 2002-02-09 bodq 335 | + Added --address option to bind to given IP addess 336 | 337 | 2001-04-15 root 338 | + Added this file so that automake won't complain. 339 | + Commented out the test for res_init in configure.in; 340 | it does not work for GLIBC2 systems (e.g., RedHat 7+). 341 | + Fixed the subordinate CHECK_LIBS on the test for res_mkquery, 342 | so that they test for res_mkquery, not res_init. 343 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | WHAT IS MTR? 2 | 3 | mtr combines the functionality of the 'traceroute' and 'ping' programs 4 | in a single network diagnostic tool. 5 | 6 | As mtr starts, it investigates the network connection between the host 7 | mtr runs on and a user-specified destination host. After it 8 | determines the address of each network hop between the machines, 9 | it sends a sequence ICMP ECHO requests to each one to determine the 10 | quality of the link to each machine. As it does this, it prints 11 | running statistics about each machine. 12 | 13 | mtr is distributed under the GNU General Public License version 2. 14 | See the COPYING file for details. 15 | 16 | INSTALLING 17 | 18 | If you're building this from a tarball, compiling mtr should be as 19 | simple as: 20 | 21 | make 22 | 23 | It should first call the "configure" script and then run "make" again 24 | with the makefile that "configure" just generated. 25 | 26 | If you're building from the git repository, you'll need to run: 27 | 28 | ./bootstrap.sh && ./configure && make 29 | 30 | After compiling, install: 31 | 32 | make install 33 | 34 | Note that mtr must be suid-root because it requires access to raw IP 35 | sockets. See SECURITY for security information. 36 | 37 | Older versions used to require a non-existant path to GTK for a 38 | correct build of a non-gtk version while GTK was installed. This is 39 | no longer neccesary. ./configure --WITHOUT_GTK should now work. 40 | If it doesn't, try "make WITHOUT_X11=YES" as the make step. 41 | 42 | On Solaris (and possibly other systems) the "gtk" library may be 43 | installed in a directory where the dynamic linker refuses to look when 44 | a binary is setuid. Roman Shterenzon reports that adding 45 | -Wl,-rpath=/usr/lib 46 | to the commandline will work if you are using gnu LD. He tells me that 47 | you're out of luck when you use the sun LD. That's not quite true, as 48 | you can move the gtk libraries to /usr/lib instead of leaving them in 49 | /usr/local/lib. (when the ld tells you that /usr/local/lib is untrusted 50 | and /usr/lib is trusted, and you trust hte gtk libs enough to want them 51 | in a setuid program, then there is something to say for moving them 52 | to the "trusted" directory.) 53 | 54 | On Solaris, linking usually fails to find "wattr" or something like that. 55 | Somehow, I can't seem to be able to automate "configure" finding the right 56 | libs on Solaris. So, the solution is that you cut-and-paste the line 57 | doing the linking into a terminal window, and add "-lcurses" by hand. 58 | Then it will link. Help on how to catch this in autoconf appreciated. 59 | 60 | On Mac OS X the nameserver8_compat.h needs to be included. I put the 61 | include inside an "#if 0" section in the file "dns.c". If someone 62 | knows how to make this automatic using autoconf / the configure script, 63 | please tell me.... 64 | 65 | This should now also work: 66 | ./configure CFLAGS="-arch i386 -arch x86_64" LIBS="-lresolv" \ 67 | --without-gtk --disable-endian-check --disable-dependency-tracking 68 | 69 | 70 | 71 | WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION? 72 | 73 | mtr is now hosted on github. 74 | https://github.com/traviscross/mtr 75 | 76 | See the mtr web page at 77 | http://www.BitWizard.nl/mtr/ 78 | 79 | There used to be a mailinglist, but all it got was spam. So 80 | when the server was upgraded, the mailing list died. 81 | 82 | Bug reports and feature requests should be submitted to the 83 | bug tracker at launchpad: https://launchpad.net/mtr/+bugs 84 | 85 | Patches can be submitted by Email to me, or submitted to the 86 | bug tracker. Or you can clone the github repository and issue a pull 87 | request. Please use unified diffs. Usually the diff is sort of 88 | messy, so please check that the diff is clean and doesn't contain too 89 | much of your local stuff (for example, I don't want/need the "configure" 90 | script that /your/ automake made for you). 91 | 92 | -- REW 93 | 94 | -------------------------------------------------------------------------------- /README.graphcairo: -------------------------------------------------------------------------------- 1 | 2 | NetBSD pkgsrc: http://pkgsrc-wip.cvs.sourceforge.net/viewvc/pkgsrc-wip/wip/mtr-graph/ 3 | FreeBSD port: http://sourceforge.net/p/freebsdwip/code/HEAD/tree/net/mtr-graph/ 4 | 5 | To build mtr with graphcairo you need to install - 6 | XCB backend: cairo >= 1.12 pango cairo-xcb xcb xcb-keysyms 7 | Xlib backend: cairo pango cairo-xlib x11 8 | 9 | Ubuntu packages: 10 | XCB: libcairo(-dev) libpango(-dev) libxcb(-dev) libxcb-keysyms(-dev) 11 | Xlib: libcairo(-dev) libpango(-dev) libx11(-dev) 12 | FreeBSD packages: 13 | XCB: cairo >= 1.12 (see http://people.freebsd.org/~kwm/cairo-1.12-CFT.txt) 14 | pango libxcb xcb-util-keysyms 15 | Xlib: cairo pango libX11 16 | NetBSD packages: 17 | XCB: cairo pango libxcb xcb-util-keysyms 18 | Xlib: cairo pango libX11 19 | OpenIndiana packages: 20 | Xlib: cairo pango libx11 21 | 22 | 23 | Build and run instructions: 24 | ./bootstrap.sh 25 | ./configure --with-graphcairo-xcb 26 | make 27 | ./mtr -G, hostname 28 | 29 | 30 | 31 | graphcairo arguments (-G args): 32 | Available arguments: 33 | 1st argument: graph type 34 | 1 - dot, 2 - line, 3 - curve (default) 35 | 2nd argument: viewport timeperiod 36 | in N ticks, one tick - 10sec (default - 6, i.e. 60sec) 37 | 3rd argument: enable legend 38 | 0 - none, 1 - enable (default) 39 | 4th argument: enable multipath 40 | 0 - none, 1 - enable (default) 41 | 5th argument: jitter graph instead of latency graph 42 | 0 - none (default), 1 - enable 43 | 44 | Examples: 45 | -G, (default: 3,6,1,1,0 - curve, 1min, legend, multipath, latency) 46 | -G2 (line, default, default, default, default) 47 | -G,30,,0 (default, 5min, default, disable, default) 48 | 49 | 50 | 51 | graphcairo keys support: `dejnpqrtuyz+- ' 52 | 53 | 54 | ---------------------------- 55 | 56 | IDN support: 57 | ./configure --with-libidn ... 58 | ... 59 | % mtr köthe.de 60 | % mtr はじめよう.みんな 61 | 62 | ---------------------------- 63 | 64 | Unicode histogram support: 65 | ./configure --with-unicode ... 66 | ... 67 | % mtr -d3 ... 68 | % mtr -d11 ... 69 | 70 | ---------------------------- 71 | 72 | System's own getopt: 73 | ./configure --with-sys-getopt ... 74 | 75 | -------------------------------------------------------------------------------- /SECURITY: -------------------------------------------------------------------------------- 1 | SECURITY ISSUES RELATED TO MTR 2 | 3 | You can limit mtr usage to the root user by not putting a setuid bit 4 | on the mtr binary. In that case, the security implications are 5 | minimal. 6 | 7 | Or you can make mtr setuid-root, and the following applies to you.... 8 | 9 | Since mtr is installed as suid-root, some concern over security is 10 | justified. Since version 0.21, mtr does the following two things 11 | after it is launched: 12 | 13 | * mtr requests a pair of raw sockets from the kernel. 14 | * mtr drops root privileges by setting the effective uid to match 15 | uid or the user calling mtr. 16 | 17 | See main() in mtr.c and net_preopen() in net.c for the details of this 18 | process. Note that no code from GTK+ or curses is executed before 19 | dropping root privileges. 20 | 21 | This should severely limit the possibilities of using mtr to breach 22 | system security. This means the worst case scenerio is as follows: 23 | 24 | Due to some oversight in the mtr code, a malicious user is able to 25 | overrun one of mtr's internal buffers with binary code that is 26 | eventually executed. The malicious user is still not able to read 27 | from or write to any system files which they wouldn't normally have 28 | permission to read or write to, repectively. The only privilege 29 | gained is access to the raw socket descriptors, which would allow 30 | the malicious user to listen to all ICMP packets arriving at the 31 | system, and to send forged packets with arbitrary contents. 32 | 33 | The mtr-code does its best to prevent calling of external library 34 | code before dropping privileges. It seems that C++ library code has 35 | the ability to issue a "please execute me before calling main" to the 36 | loader/linker. That would mean that we're still vulnerable to 37 | errors in that code. This is why I would prefer to drop the backends, 38 | have mtr-core always run in "raw" mode, and have the backends interpret 39 | the output from the mtr-core. Maybe a nice project for a college-level 40 | student. 41 | 42 | If you have further questions or comments about security issues, 43 | please direct them to the mtr mailing list. See README for details. 44 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | Hi everyone, 3 | 4 | This is the "todo" file for mtr. I just realized that some people 5 | might think that this is all in MY queue to implement. That is not 6 | true: This is the "for everybody" todo list. Feel free to pick a 7 | "project" and implement something off this list. 8 | 9 | Students: Feel free to take up one of these as a programming exercise 10 | for one of your courses. 11 | 12 | Everybody: If you want to start on something, contact me first, so 13 | that the effort isn't wasted by someone who finishes just a tad 14 | earlier. I'll happily provide "coaching" to anyone who wants to 15 | implement something on this list. That way we get the design of 16 | these things the way I like them. This should result in a better 17 | maintainable mtr. 18 | 19 | Oh, Feel free to provide suggestions for this list. 20 | 21 | 22 | -- REW 23 | 24 | ---------------------------------------------------------------------- 25 | 26 | 27 | - Stuff to implement: 28 | 29 | - Allow mtr to log the return packets, for later analysis. 30 | Done: 0.25 . Todo: allow the user interface(s) to work while 31 | still logging to a file. Write a "logfile displaying" mode to 32 | mtr. 33 | 34 | - Request timestamping at the remote site. 35 | Andreas Fasbender has an algorithm that will allow us to 36 | convert these measurements into one-way measurements, not just 37 | round-trip. 38 | 39 | - allow "keyboard navigation" in the GTK version. 40 | 41 | - Keep all packets and make the "best" and "worst" columns show the 42 | xx-th percentile.... 43 | 44 | - Can the reports generated also include any secondary servers? In 45 | the interactive mode, any new servers that are found in the 46 | traceroute are added to the list, but it seems to only include 47 | one set of servers when using the -r option. 48 | 49 | - Being able to expand the "column width" of the hosts listed would 50 | be nice, too. 51 | 52 | 53 | - Bugs to fix? 54 | 55 | - Do something useful if host couldn't be resolved. 56 | -- Done. 57 | 58 | - Revert to curses mode even if DISPLAY is set, but a problem 59 | prevents us from running in X11 mode. 60 | --> The problem is that gtk_init simply calls exit for us if 61 | it finds a problem. Tricky! Suggestions welcome. 62 | --> Call "gtk_check_init" when available. (i.e. new enough 63 | (1.2?) GTK version). 64 | 65 | - Nice to have: 66 | 67 | - stop sending packets when a new host is getting entered. 68 | 69 | - Show state ("looking up host") while doing the DNS lookup for a new 70 | host. 71 | 72 | - to have a choice of icmp, tcp, and udp pings. -- Matt Martini 73 | 74 | - Autoconf 2.13 has a neat function that can be used to find the 75 | res_init function: 76 | 77 | AC_SEARCH_LIBS(res_init, bind resolv, , 78 | AC_MSG_ERROR(No resolver library found)) 79 | 80 | At the moment (march 1999) autoconf 2.13 is still too new to require 81 | everyone to upgrade. About a year from now we can put this in.... 82 | 83 | - Implement rfc2317 mechanism to do reverse lookups for networks that 84 | have DNS delegations on non-octet boundaries. -- Daniel Bergstrom 85 | (noa@melody.se) 86 | 87 | - The longer MTR runs, the less meaningful the packet loss 88 | statistic. Or more meaningful, depending on your point of view. 89 | Perhaps MTR should use a circular buffer of some configurable 90 | number of results, and calculate the loss against that. -- Jacob Elder 91 | 92 | - It would be nice if the window size wasn't fixed. If I'm only 5 93 | hops from the host I'm monitoring, MTR wastes a lot of screen real 94 | estate. -- Jacob Elder 95 | 96 | - Colors in the curses version. -- Amix 97 | 98 | - If we run a mtr to monitor a connection it would be nice if the time at 99 | which mtr was started is print somewhere. -- Sebastian Ganschow 100 | 101 | 102 | 103 | ------------------------------------------------------------------------ 104 | 105 | Things that shouldn't be on the TODO list because they're done. ;-) 106 | 107 | - Allow a toggle between hostname/IP number display. (for example a 108 | click on the hostname could revert to ip number display in gtk version. 109 | curses: "n" key toggles hostnames/ipnumbers?) 110 | 111 | - Allow mtr to also send larger packets. 112 | This will enable us to get a feel for the speed of the links 113 | we're traversing. (Van Jacobson was working on this His tool 114 | was slow, mtr will rock with this feature.... :-) 115 | (Anybody have the statistics experience to tell me how 116 | to do the data analysis?) 117 | -- DONE. Thanks to Olav Kvittem ... 118 | 119 | - The "don't probe all hosts at once" strategy can be improved a bit. 120 | It should not probe more than 10 unknown hosts, but the counter need 121 | not be reset at the start of the "round". This way if you probe 122 | slowly (relative to the RTT time to the end host), it can probe 123 | all hosts in the first "round". 124 | -- DONE. 125 | 126 | - Read environment variable "MTR_DEFAULTS" as a commandline before 127 | parsing the commandline. -- DONE. (ok it's MTR_OPTIONS.) 128 | 129 | -------------------------------------------------------------------------------- /asn.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #ifdef __APPLE__ 27 | #define BIND_8_COMPAT 28 | #endif 29 | #include 30 | #ifdef HAVE_ARPA_NAMESER_COMPAT_H 31 | #include 32 | #endif 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "mtr.h" 41 | #include "asn.h" 42 | 43 | /* 44 | #ifndef IIDEBUG 45 | #define IIDEBUG 46 | #endif 47 | */ 48 | 49 | #ifdef IIDEBUG 50 | #include 51 | #define IIDEBUG_MSG(x) syslog x 52 | #else 53 | #define IIDEBUG_MSG(x) 54 | #endif 55 | 56 | #define II_ARGS_SEP ',' 57 | #define II_ITEM_SEP '|' 58 | #define II_ITEM_MAX 5 59 | #define NAMELEN 128 60 | #define UNKN "???" 61 | 62 | extern int af; /* address family of remote target */ 63 | extern int maxTTL; 64 | 65 | int enable_ipinfo; 66 | 67 | static int hash; 68 | static int origin_no; 69 | static int ipinfo_no[II_ITEM_MAX] = {-1}; 70 | static int ipinfo_max; 71 | 72 | typedef char* items_t[II_ITEM_MAX]; 73 | static items_t* items; 74 | 75 | typedef struct { 76 | char* ip4zone; 77 | char* ip6zone; 78 | int as_prfx_ndx; 79 | int fields; 80 | int width[II_ITEM_MAX]; 81 | } origin_t; 82 | static origin_t origins[] = { 83 | // ASN [ASN ..] | Route | CC | Registry | Allocated 84 | { "origin.asn.cymru.com", "origin6.asn.cymru.com", 0, 5, { 6, 17, 4, 8, 11 } }, 85 | // ASN 86 | { "asn.routeviews.org", NULL, 0, 1, { 6 } }, 87 | // Route | "AS"ASN | Organization | Allocated | CC 88 | { "origin.asn.spameatingmonkey.net", NULL, -1, 5, { 17, 8, 17, 11, 4 } }, 89 | }; 90 | 91 | char *ipinfo_lookup(const char *domain) { 92 | unsigned char answer[PACKETSZ], *pt; 93 | char host[128]; 94 | char *txt; 95 | int len, exp, size, txtlen, type; 96 | static char txtrec[NAMELEN]; 97 | 98 | if(res_init() < 0) { 99 | fprintf(stderr,"@res_init failed\n"); 100 | return NULL; 101 | } 102 | 103 | memset(answer, 0, PACKETSZ); 104 | if((len = res_query(domain, C_IN, T_TXT, answer, PACKETSZ)) < 0) { 105 | #ifdef IIDEBUG 106 | if (hash) 107 | syslog(LOG_INFO, "Malloc-txt: %s", UNKN); 108 | #endif 109 | return (hash)?strdup(UNKN):UNKN; 110 | } 111 | 112 | pt = answer + sizeof(HEADER); 113 | 114 | if((exp = dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) { 115 | printf("@dn_expand failed\n"); return NULL; 116 | } 117 | 118 | pt += exp; 119 | 120 | GETSHORT(type, pt); 121 | if(type != T_TXT) { 122 | printf("@Broken DNS reply.\n"); return NULL; 123 | } 124 | 125 | pt += INT16SZ; /* class */ 126 | 127 | if((exp = dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) { 128 | printf("@second dn_expand failed\n"); return NULL; 129 | } 130 | 131 | pt += exp; 132 | GETSHORT(type, pt); 133 | if(type != T_TXT) { 134 | printf("@Not a TXT record\n"); return NULL; 135 | } 136 | 137 | pt += INT16SZ; /* class */ 138 | pt += INT32SZ; /* ttl */ 139 | GETSHORT(size, pt); 140 | txtlen = *pt; 141 | 142 | 143 | if(txtlen >= size || !txtlen) { 144 | printf("@Broken TXT record (txtlen = %d, size = %d)\n", txtlen, size); return NULL; 145 | } 146 | 147 | if (txtlen > NAMELEN) 148 | txtlen = NAMELEN; 149 | 150 | if (hash) { 151 | if (!(txt = malloc(txtlen + 1))) 152 | return NULL; 153 | } else 154 | txt = (char*)txtrec; 155 | 156 | pt++; 157 | strncpy(txt, (char*) pt, txtlen); 158 | txt[txtlen] = 0; 159 | 160 | #ifdef IIDEBUG 161 | if (hash) 162 | syslog(LOG_INFO, "Malloc-txt(%p): %s", txt, txt); 163 | #endif 164 | 165 | return txt; 166 | } 167 | 168 | int split_with_sep(char** args, int max, char sep) { 169 | if (!*args) 170 | return 0; 171 | 172 | int i; 173 | char *p = *args, **a = args + 1; 174 | for (i = 0; (p = strchr(p, sep)) && (i < max); i++) { 175 | *p++ = 0; 176 | if ((i + 1) < max) 177 | *a++ = p; 178 | } 179 | int j; 180 | for (j = 0; j < max; j++) 181 | if (args[j]) 182 | args[j] = trim(args[j]); 183 | 184 | return (i + 1); 185 | } 186 | 187 | char* split_rec(char *rec, int ndx) { 188 | if (!rec) 189 | return NULL; 190 | if (hash) { 191 | IIDEBUG_MSG((LOG_INFO, "Malloc-tbl: %s", rec)); 192 | if (!(items = malloc(sizeof(*items)))) { 193 | IIDEBUG_MSG((LOG_INFO, "Free-txt(%p)", rec)); 194 | free(rec); 195 | return NULL; 196 | } 197 | } else { 198 | IIDEBUG_MSG((LOG_INFO, "Not hashed: %s", rec)); 199 | static items_t nothashed_items; 200 | items = ¬hashed_items; 201 | } 202 | 203 | memset(items, 0, sizeof(*items)); 204 | (*items)[0] = rec; 205 | int i = split_with_sep((char**)items, II_ITEM_MAX, II_ITEM_SEP); 206 | 207 | if (i > ipinfo_max) 208 | ipinfo_max = i; 209 | 210 | // special cases 211 | switch (origin_no) { 212 | case 0: // cymru.com: MultiAS 213 | if (origins[0].as_prfx_ndx < i) { 214 | char *p = (*items)[origins[0].as_prfx_ndx]; 215 | if (p) { 216 | char *last = p + strlen(p) - 1; 217 | while ((p = strchr(p, ' '))) 218 | if (p != last) 219 | *p = '/'; 220 | else 221 | break; 222 | } 223 | } break; 224 | case 1: { // originviews.org: unknown AS 225 | #define S_UINT32_MAX "4294967295" 226 | int j; 227 | for (j = 0; (j < i) && (*items)[j]; j++) 228 | if (!strncmp((*items)[j], S_UINT32_MAX, sizeof(S_UINT32_MAX))) 229 | (*items)[j] = UNKN; 230 | } break; 231 | case 2: { // spameatingmonkey.net: unknown info 232 | #define Unknown "Unknown" 233 | int j; 234 | for (j = 0; (j < i) && (*items)[j]; j++) 235 | if (!strncmp((*items)[j], Unknown, sizeof(Unknown))) 236 | (*items)[j] = UNKN; 237 | } break; 238 | } 239 | 240 | return (ipinfo_no[ndx] < i) ? (*items)[ipinfo_no[ndx]] : (*items)[0]; 241 | } 242 | 243 | #ifdef ENABLE_IPV6 244 | // from dns.c:addr2ip6arpa() 245 | void reverse_host6(struct in6_addr *addr, char *buff) { 246 | int i; 247 | char *b = buff; 248 | for (i=(sizeof(*addr)/2-1); i>=0; i--, b+=4) // 64b portion 249 | sprintf(b, "%x.%x.", addr->s6_addr[i] & 0xf, addr->s6_addr[i] >> 4); 250 | buff[strlen(buff) - 1] = 0; 251 | } 252 | #endif 253 | 254 | char *get_ipinfo(ip_t *addr, int ndx) { 255 | if (!addr) 256 | return NULL; 257 | 258 | char key[NAMELEN]; 259 | char lookup_key[NAMELEN]; 260 | 261 | if (af == AF_INET6) { 262 | #ifdef ENABLE_IPV6 263 | if (!origins[origin_no].ip6zone) 264 | return NULL; 265 | reverse_host6(addr, key); 266 | sprintf(lookup_key, "%s.%s", key, origins[origin_no].ip6zone); 267 | #else 268 | return NULL; 269 | #endif 270 | } else { 271 | if (!origins[origin_no].ip4zone) 272 | return NULL; 273 | unsigned char buff[4]; 274 | memcpy(buff, addr, 4); 275 | sprintf(key, "%d.%d.%d.%d", buff[3], buff[2], buff[1], buff[0]); 276 | sprintf(lookup_key, "%s.%s", key, origins[origin_no].ip4zone); 277 | } 278 | 279 | char *val = NULL; 280 | ENTRY item; 281 | 282 | if (hash) { 283 | IIDEBUG_MSG((LOG_INFO, ">> Search: %s", key)); 284 | item.key = key; 285 | ENTRY *found_item; 286 | if ((found_item = hsearch(item, FIND))) { 287 | if (!(val = (*((items_t*)found_item->data))[ipinfo_no[ndx]])) 288 | val = (*((items_t*)found_item->data))[0]; 289 | IIDEBUG_MSG((LOG_INFO, "Found (hashed): %s", val)); 290 | } 291 | } 292 | 293 | if (!val) { 294 | IIDEBUG_MSG((LOG_INFO, "Lookup: %s", key)); 295 | if ((val = split_rec(ipinfo_lookup(lookup_key), ndx))) { 296 | IIDEBUG_MSG((LOG_INFO, "Looked up: %s", key)); 297 | if (hash) 298 | if ((item.key = strdup(key))) { 299 | item.data = (void*)items; 300 | hsearch(item, ENTER); 301 | #ifdef IIDEBUG 302 | { 303 | char buff[NAMELEN] = {0}; 304 | int i, len = 0; 305 | for (i = 0; (i < II_ITEM_MAX) && (*items)[i]; i++) { 306 | sprintf(buff + len, "\"%s\" ", (*items)[i]); 307 | len = strlen(buff); 308 | } 309 | syslog(LOG_INFO, "Insert into hash: \"%s\" => %s", key, buff); 310 | } 311 | #endif 312 | } 313 | } 314 | } 315 | 316 | return val; 317 | } 318 | 319 | int ii_getwidth(void) { 320 | int i, l = 0; 321 | for (i = 0; (i < II_ITEM_MAX) && (ipinfo_no[i] >= 0); i++) { 322 | l += origins[origin_no].width[ipinfo_no[i]]; 323 | if (ipinfo_no[i] == origins[origin_no].as_prfx_ndx) 324 | l += 2; // AS prfx 325 | } 326 | return l; 327 | } 328 | 329 | char *fmt_ipinfo(ip_t *addr) { 330 | static char fmtinfo[NAMELEN]; 331 | char fmt[16]; 332 | int len = 0; 333 | int i; 334 | for (i = 0; (i < II_ITEM_MAX) && (ipinfo_no[i] >= 0); i++) { 335 | char *ipinfo = get_ipinfo(addr, i); 336 | int width = origins[origin_no].width[ipinfo_no[i]]; 337 | if (ipinfo) { 338 | int l = strlen(ipinfo); 339 | if (!l) 340 | ipinfo = UNKN; 341 | if ((l >= width) && (width > 0)) 342 | ipinfo[width - 1] = 0; 343 | } else 344 | ipinfo = UNKN; 345 | sprintf(fmt, "%s%%-%ds", (ipinfo_no[i] == origins[origin_no].as_prfx_ndx) ? "AS" : "", width); 346 | sprintf(fmtinfo + len, fmt, ipinfo); 347 | len = strlen(fmtinfo); 348 | } 349 | return fmtinfo; 350 | } 351 | 352 | void asn_open(void) { 353 | if (!hash) { 354 | IIDEBUG_MSG((LOG_INFO, "hcreate(%d)", maxTTL)); 355 | if (!(hash = hcreate(maxTTL))) 356 | perror("ipinfo hash"); 357 | } 358 | } 359 | 360 | void asn_close(void) { 361 | if (hash) { 362 | IIDEBUG_MSG((LOG_INFO, "hdestroy()")); 363 | hdestroy(); 364 | hash = enable_ipinfo = 0; 365 | } 366 | } 367 | 368 | void ii_parsearg(char *arg) { 369 | if (!hash) 370 | asn_open(); 371 | 372 | char* args[II_ITEM_MAX + 1]; 373 | memset(args, 0, sizeof(args)); 374 | if (arg) { 375 | args[0] = strdup(arg); 376 | split_with_sep((char**)&args, II_ITEM_MAX + 1, II_ARGS_SEP); 377 | int no = atoi(args[0]); 378 | if ((no > 0) && (no <= (sizeof(origins)/sizeof(origins[0])))) 379 | origin_no = no - 1; 380 | } 381 | 382 | int i, j; 383 | for (i = 1, j = 0; (j < II_ITEM_MAX) && (i <= II_ITEM_MAX); i++) 384 | if (args[i]) { 385 | int no = atoi(args[i]); 386 | if ((no > 0) && (no <= origins[origin_no].fields)) 387 | ipinfo_no[j++] = no - 1; 388 | } 389 | for (i = j; i < II_ITEM_MAX; i++) 390 | ipinfo_no[i] = -1; 391 | if (ipinfo_no[0] < 0) 392 | ipinfo_no[0] = 0; 393 | 394 | if (args[0]) 395 | free(args[0]); 396 | enable_ipinfo = 1; 397 | IIDEBUG_MSG((LOG_INFO, "ii origin: \"%s\" \"%s\"", origins[origin_no].ip4zone, origins[origin_no].ip6zone)); 398 | } 399 | 400 | void ii_action(int action_asn) { 401 | if (!hash) 402 | asn_open(); 403 | 404 | if (ipinfo_no[0] >= 0) { 405 | if (action_asn) 406 | enable_ipinfo = !enable_ipinfo; 407 | else { 408 | int i; 409 | for (i = 0; (i < II_ITEM_MAX) && (ipinfo_no[i] >= 0); i++) { 410 | ipinfo_no[i]++; 411 | if (!i) 412 | enable_ipinfo = (ipinfo_no[0] < ipinfo_max) ? 1 : 0; 413 | if (ipinfo_no[i] >= ipinfo_max) 414 | ipinfo_no[i] = 0; 415 | } 416 | } 417 | } else // init 418 | ii_parsearg(NULL); 419 | } 420 | 421 | -------------------------------------------------------------------------------- /asn.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #ifndef ASN_H 20 | #define ASN_H 21 | 22 | // The autoconf system provides us with the NO_IPINFO define. 23 | // Littering the code with #ifndef NO_IPINFO (double negative) 24 | // does not benefit readabilty. So here we invert the sense of the 25 | // define. 26 | // 27 | // Similarly, this include file should be included unconditially. 28 | // It will evaluate to nothing if we don't need it. 29 | 30 | #ifndef NO_IPINFO 31 | #define IPINFO 32 | 33 | extern int enable_ipinfo; 34 | void asn_close(); 35 | char *fmt_ipinfo(ip_t *addr); 36 | void ii_parsearg(char *arg); 37 | void ii_action(int action_asn); 38 | int ii_getwidth(void); 39 | 40 | #endif 41 | #endif 42 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | aclocal 4 | autoheader 5 | automake --add-missing --copy --foreign 6 | autoconf 7 | 8 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([mtr], [0.85]) 2 | AC_CONFIG_SRCDIR([mtr.c]) 3 | AM_INIT_AUTOMAKE([foreign subdir-objects]) 4 | 5 | AC_CONFIG_FILES([version.h.tmp:version.h.in]) 6 | 7 | AC_SUBST(GTK_OBJ) 8 | AC_SUBST(CURSES_OBJ) 9 | 10 | GTK_OBJ=gtk.o 11 | CURSES_OBJ=curses.o 12 | 13 | AC_PROG_CC 14 | AM_PROG_CC_C_O 15 | AC_PROG_RANLIB 16 | 17 | AC_CHECK_SIZEOF(unsigned char, 1) 18 | AC_CHECK_SIZEOF(unsigned short, 2) 19 | AC_CHECK_SIZEOF(unsigned int, 4) 20 | AC_CHECK_SIZEOF(unsigned long, 4) 21 | 22 | AC_CHECK_HEADERS(sys/types.h fcntl.h socket.h sys/socket.h sys/xti.h arpa/nameser_compat.h) 23 | 24 | AC_ARG_WITH(unicode, 25 | [ --with-unicode Do try to use unicode], 26 | [unicode=${withval}], [unicode=no]) 27 | AS_IF([test "x$unicode" = "xyes"], [ 28 | AC_CHECK_HEADERS([ncursesw/cursesw.h ncursesw/curses.h curses.h], break) 29 | AC_CHECK_HEADERS([wchar.h wctype.h locale.h langinfo.h]) 30 | AC_SEARCH_LIBS([add_wch], [ncursesw curses], # Ncursesw and X/Open curses provide add_wch() 31 | AC_DEFINE([UNICODE], [1], [Define to enable unicode]), 32 | AC_MSG_ERROR([No wide-character curses library found])) 33 | AC_SEARCH_LIBS([tgetent], [ncursesw curses termcap tinfo]) # don't leak ncursesw/curses in LIBS 34 | AC_SEARCH_LIBS([use_default_colors], [ncursesw curses], 35 | AC_DEFINE([HAVE_USE_DEFAULT_COLORS], [1], [Define this if your curses library has the use_default_colors() command.])) 36 | ], [ 37 | 38 | AC_CHECK_HEADERS(ncurses.h ncurses/curses.h curses.h cursesX.h, break) 39 | 40 | # We don't refer to any symbols in termcap, but -lcurses on SunOS does. 41 | # We have to trust the linker not to mess things up... (It should not 42 | # pull in anything if we don't refer to anything in the lib). 43 | AC_CHECK_LIB(termcap, tgetent) 44 | AC_CHECK_LIB(tinfo, tgetent) 45 | 46 | AC_CHECK_FUNC(initscr, , 47 | AC_CHECK_LIB(ncurses, initscr, , 48 | AC_CHECK_LIB(curses, initscr, , 49 | AC_CHECK_LIB(cursesX, initscr, , 50 | AC_MSG_WARN(Building without curses display support) 51 | AC_DEFINE(NO_CURSES, 1, Define if you don't have the curses libraries available.) 52 | CURSES_OBJ=)))) 53 | 54 | AC_SEARCH_LIBS([use_default_colors], [ncurses curses], 55 | AC_DEFINE(HAVE_USE_DEFAULT_COLORS, 1, [Define this if your curses library has the use_default_colors() command.])) 56 | ]) 57 | 58 | AC_CHECK_FUNCS(attron fcntl) 59 | 60 | AC_CHECK_LIB(m, floor, , AC_MSG_ERROR(No math library found)) 61 | 62 | AC_ARG_WITH(gtk, 63 | [ --without-gtk Do not try to use GTK+ at all], 64 | WANTS_GTK=$withval, WANTS_GTK=yes) 65 | 66 | AC_ARG_WITH([ipinfo], 67 | [ --without-ipinfo Do not try to use ipinfo lookup at all], 68 | [ipinfo="${withval}"], [ipinfo=yes]) 69 | AM_CONDITIONAL([IPINFO], [test "x$ipinfo" = "xyes"]) 70 | 71 | AC_ARG_WITH([graphcairo_xcb], 72 | [ --with-graphcairo-xcb Do try to use cairo graph with XCB backend], 73 | [graphcairo_xcb="${withval}"], [graphcairo_xcb=no]) 74 | AM_CONDITIONAL([GRAPHCAIRO_XCB], [test "x$graphcairo_xcb" = "xyes"]) 75 | 76 | AC_ARG_WITH([graphcairo_xlib], 77 | [ --with-graphcairo-xlib Do try to use cairo graph with Xlib backend], 78 | [graphcairo_xlib="${withval}"], [graphcairo_xlib=no]) 79 | AM_CONDITIONAL([GRAPHCAIRO_XLIB], [test "x$graphcairo_xlib" = "xyes"]) 80 | 81 | AM_CONDITIONAL([GRAPHCAIRO], [test "x$graphcairo_xcb" = "xyes" -o "x$graphcairo_xlib" = "xyes"]) 82 | 83 | AC_ARG_WITH([libidn], 84 | [ --with-libidn Do try to use libidn], 85 | [libidn="${withval}"], [libidn=no]) 86 | AM_CONDITIONAL([LIBIDN], [test "x$libidn" = "xyes"]) 87 | 88 | AC_ARG_WITH([sys_getopt], 89 | [ --with-sys-getopt Do try to use system getopt], 90 | [sys_getopt="${withval}"], [sys_getopt=no]) 91 | AM_CONDITIONAL([LOCAL_GETOPT], [test "x$sys_getopt" = "xno"]) 92 | 93 | AC_ARG_ENABLE(ipv6, 94 | [ --disable-ipv6 Do not enable IPv6], 95 | WANTS_IPV6=$enableval, WANTS_IPV6=yes) 96 | 97 | m4_ifndef([AM_PATH_GTK_2_0], [m4_defun([AM_PATH_GTK_2_0], [AC_MSG_ERROR([ 98 | Could not locate the gtk2 automake macros, these are usually located in 99 | .../share/aclocal/gtk-2.0.m4 100 | Before running bootstrap try setting the environment variable 101 | ACLOCAL_PATH="/own/dir" 102 | or configure --without-gtk. 103 | ])])]) 104 | 105 | if test "x$WANTS_GTK" = "xyes"; then 106 | AM_PATH_GTK_2_0(2.6.0, CFLAGS="$CFLAGS $GTK_CFLAGS" 107 | LIBS="$LIBS $GTK_LIBS -lm", 108 | AC_MSG_WARN(Building without GTK2 display support) 109 | AC_DEFINE(NO_GTK, 1, [Define if you don't have the GTK+ libraries available.]) 110 | GTK_OBJ="") 111 | else 112 | AC_DEFINE(NO_GTK) 113 | GTK_OBJ="" 114 | fi 115 | 116 | if test "x$ipinfo" = "xno"; then 117 | AC_DEFINE([NO_IPINFO], [1], [Define to disable ipinfo lookup]) 118 | fi 119 | 120 | m4_ifndef([PKG_CHECK_MODULES], [m4_defun([PKG_CHECK_MODULES], [AC_MSG_ERROR([ 121 | Could not locate the pkg-config automake macros, these are usually located in 122 | .../share/aclocal/pkg.m4 123 | Before running bootstrap try setting the environment variable 124 | ACLOCAL_PATH="/own/dir" 125 | or configure --without-graphcairo-* 126 | ])])]) 127 | 128 | PKG_PROG_PKG_CONFIG 129 | 130 | AS_IF([test "x$graphcairo_xcb" = "xyes"], [ 131 | AC_DEFINE([GRAPHCAIRO], [1], [Define to enable cairo graph]) 132 | PKG_CHECK_MODULES([graphcairo], [cairo >= 1.12 pango >= 1.10 pangocairo xcb xcb-keysyms cairo-xcb], [ 133 | LIBS="$LIBS -lm" 134 | AC_SUBST(graphcairo_CFLAGS) 135 | AC_SUBST(graphcairo_LIBS) 136 | AC_DEFINE([GRAPHCAIRO_XCB], [1], [Define to enable cairo XCB backend]) 137 | ]) 138 | ], [ 139 | AS_IF([test "x$graphcairo_xlib" = "xyes"], [ 140 | AC_DEFINE([GRAPHCAIRO], [1], [Define to enable cairo graph]) 141 | PKG_CHECK_MODULES([graphcairo], [cairo pango >= 1.10 pangocairo x11 cairo-xlib], [ 142 | LIBS="$LIBS -lm" 143 | AC_SUBST(graphcairo_CFLAGS) 144 | AC_SUBST(graphcairo_LIBS) 145 | AC_DEFINE([GRAPHCAIRO_XLIB], [1], [Define to enable cairo Xlib backend]) 146 | ]) 147 | ]) 148 | ]) 149 | 150 | AS_IF([test "x$libidn" = "xyes"], [ 151 | PKG_CHECK_MODULES([libidn], [libidn], [ 152 | AC_SUBST(libidn_CFLAGS) 153 | AC_SUBST(libidn_LIBS) 154 | AC_DEFINE([HAVE_LIBIDN], [1], [Define to enable libidn]) 155 | ]) 156 | ]) 157 | 158 | AS_IF([test "x$sys_getopt" = "xyes"], [ 159 | AC_CHECK_HEADERS([getopt.h]) 160 | AC_CHECK_FUNCS([getopt_long], AC_DEFINE([HAVE_GETOPT_LONG]), AC_MSG_ERROR([No system getopt_long found])) 161 | ]) 162 | 163 | AC_CANONICAL_HOST 164 | case "$host_os" in 165 | linux*) 166 | AC_DEFINE(_BSD_SOURCE, 1, [enable BSD derived definitions]) 167 | ;; 168 | solaris*) 169 | AC_DEFINE(BSD_COMP, 1, [enable BSD compatibility]) 170 | ;; 171 | netbsd*) 172 | AC_DEFINE(NETBSD_CURSES, 1, [NetBSD: a hybrid of BSD-curses with X/Open curses]) 173 | ;; 174 | esac 175 | 176 | AC_CHECK_FUNC(socket, , 177 | AC_CHECK_LIB(socket, socket, , AC_MSG_ERROR(No socket library found))) 178 | 179 | AC_CHECK_FUNC(gethostbyname, , 180 | AC_CHECK_LIB(nsl, gethostbyname, , AC_MSG_ERROR(No nameservice library found))) 181 | 182 | #AC_CHECK_FUNC(res_init, , 183 | # AC_CHECK_LIB(bind, res_init, , 184 | # AC_CHECK_LIB(resolv, res_init, , AC_MSG_ERROR(No resolver library found)))) 185 | 186 | AC_CHECK_FUNCS(seteuid) 187 | # AC_CHECK_FUNC(setuid, , AC_MSG_ERROR (I Need either seteuid or setuid)) 188 | 189 | #AC_CHECK_FUNC(res_mkquery, , 190 | # AC_CHECK_LIB(bind, res_mkquery, , 191 | # AC_CHECK_LIB(resolv, res_mkquery, , 192 | # AC_CHECK_LIB(resolv, __res_mkquery, , AC_MSG_ERROR(No resolver library found))))) 193 | 194 | # See if a library is needed for res_mkquery and if so put it in RESOLV_LIBS 195 | RESOLV_LIBS= 196 | AC_SUBST(RESOLV_LIBS) 197 | AC_DEFUN([LIBRESOLVTEST_SRC], [ 198 | AC_LANG_PROGRAM([[ 199 | #include 200 | #include 201 | ]], [[ 202 | int (*res_mkquery_func)(int,...) = (int (*)(int,...))res_mkquery; 203 | (void)(*res_mkquery_func)(0); 204 | ]])]) 205 | AC_MSG_CHECKING([whether library required for res_mkquery]) 206 | RESOLV_LIB_NONE= 207 | AC_LINK_IFELSE([LIBRESOLVTEST_SRC], 208 | [AC_MSG_RESULT([no]) 209 | RESOLV_LIB_NONE=yes], 210 | [AC_MSG_RESULT([yes])]) 211 | if test "x$RESOLV_LIB_NONE" = "x"; then 212 | AC_MSG_CHECKING([for res_mkquery in -lbind]) 213 | STASH_LIBS="$LIBS" 214 | LIBS="$STASH_LIBS -lbind" 215 | AC_LINK_IFELSE([LIBRESOLVTEST_SRC], 216 | [AC_MSG_RESULT([yes]) 217 | RESOLV_LIBS=-lbind], 218 | [AC_MSG_RESULT([no])]) 219 | if test "x$RESOLV_LIBS" = "x"; then 220 | AC_MSG_CHECKING([for res_mkquery in -lresolv]) 221 | LIBS="$STASH_LIBS -lresolv" 222 | AC_LINK_IFELSE([LIBRESOLVTEST_SRC], 223 | [AC_MSG_RESULT([yes]) 224 | RESOLV_LIBS=-lresolv], 225 | [AC_MSG_RESULT([no]) 226 | AC_MSG_ERROR(No resolver library found)]) 227 | fi 228 | LIBS="$STASH_LIBS" 229 | fi 230 | 231 | AC_CHECK_FUNC(herror, , AC_DEFINE(NO_HERROR, 1, [Define if you don't have the herror() function available.])) 232 | AC_CHECK_FUNC(strerror, , AC_DEFINE(NO_STRERROR, 1, [Define if you don't have the strerror() function available.])) 233 | 234 | USES_IPV6= 235 | AC_CHECK_FUNC(getaddrinfo, 236 | [if test "$WANTS_IPV6" = "yes"; then 237 | AC_DEFINE([ENABLE_IPV6], [], [Define to enable IPv6]) 238 | USES_IPV6=yes 239 | fi]) 240 | 241 | AC_DEFUN([NEED_RES_STATE_EXT_TEST_SRC], [ 242 | AC_LANG_PROGRAM([[ 243 | #include 244 | #include 245 | #ifdef __GLIBC__ 246 | #define RESEXTIN6(r,i) (*(r._u._ext.nsaddrs[i])) 247 | #else 248 | #define RESEXTIN6(r,i) (r._u._ext.ext->nsaddrs[i].sin6) 249 | #endif 250 | ]], [[ 251 | struct __res_state res; 252 | return RESEXTIN6(res,0).sin6_addr.s6_addr[0]; 253 | ]])]) 254 | AC_DEFUN([DEFINE_RES_STATE_EXT_TEST_SRC], [ 255 | AC_LANG_PROGRAM([[ 256 | #include 257 | #include 258 | #ifdef __GLIBC__ 259 | #define RESEXTIN6(r,i) (*(r._u._ext.nsaddrs[i])) 260 | #else 261 | #define RESEXTIN6(r,i) (r._u._ext.ext->nsaddrs[i].sin6) 262 | struct __res_state_ext { 263 | union res_sockaddr_union nsaddrs[MAXNS]; 264 | struct sort_list { 265 | int af; 266 | union { 267 | struct in_addr ina; 268 | struct in6_addr in6a; 269 | } addr, mask; 270 | } sort_list[MAXRESOLVSORT]; 271 | char nsuffix[64]; 272 | char nsuffix2[64]; 273 | }; 274 | #endif 275 | ]], [[ 276 | struct __res_state res; 277 | return RESEXTIN6(res,0).sin6_addr.s6_addr[0]; 278 | ]])]) 279 | if test "x$USES_IPV6" = "xyes"; then 280 | AC_MSG_CHECKING([whether __res_state_ext needs to be defined]) 281 | AC_COMPILE_IFELSE([NEED_RES_STATE_EXT_TEST_SRC], 282 | [AC_MSG_RESULT([no])], 283 | [AC_MSG_RESULT([yes]) 284 | AC_MSG_CHECKING([whether provided __res_state_ext definition can be compiled]) 285 | AC_COMPILE_IFELSE([DEFINE_RES_STATE_EXT_TEST_SRC], 286 | [AC_MSG_RESULT([yes]) 287 | AC_DEFINE(NEED_RES_STATE_EXT, 1, [Define if struct __res_state_ext needs to be defined.])], 288 | [AC_MSG_RESULT([no]) 289 | AC_MSG_ERROR(Need definition for struct __res_state_ext but unable to define it.)])]) 290 | fi 291 | 292 | AC_CHECK_DECLS(errno, , , [[ 293 | #include 294 | #include 295 | ]] ) 296 | 297 | AC_CHECK_TYPE(socklen_t, AC_DEFINE([HAVE_SOCKLEN_T], [], [Define if your system has socklen_t]) , , [[ 298 | #include 299 | #ifdef HAVE_SOCKET_H 300 | #include 301 | #endif 302 | #ifdef HAVE_SYS_SOCKET_H 303 | #include 304 | #endif 305 | ]]) 306 | 307 | AC_CHECK_TYPE(struct in_addr, AC_DEFINE([HAVE_STRUCT_INADDR], [], [Define if you have struct in_addr]), , [[ 308 | #include 309 | ]]) 310 | 311 | dnl Add C flags to display more warnings 312 | AC_MSG_CHECKING(for C flags to get more warnings) 313 | ac_save_CFLAGS="$CFLAGS" 314 | if test "x$ac_cv_c_compiler_gnu" = "xyes" ; then 315 | dnl gcc is the easiest C compiler 316 | warning_CFLAGS="-Wall" 317 | # Check if compiler supports -Wno-pointer-sign and add it if supports 318 | CFLAGS_saved="$CFLAGS" 319 | CFLAGS="$CFLAGS -Wno-pointer-sign" 320 | AC_COMPILE_IFELSE([ AC_LANG_SOURCE([[ int foo; ]])], 321 | [ warning_CFLAGS="${warning_CFLAGS} -Wno-pointer-sign" ],) 322 | CFLAGS="$CFLAGS_saved" 323 | else 324 | dnl Vendor supplied C compilers are a bit tricky 325 | case "$host_os" in 326 | dnl SGI IRIX with the MipsPRO C compiler 327 | irix*) 328 | CFLAGS="$CFLAGS -fullwarn" 329 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[printf("test");]])],[warning_CFLAGS="-fullwarn"],[]) 330 | ;; 331 | 332 | dnl SunOS 4.x with the SparcWorks(?) acc compiler 333 | sunos*) 334 | if "$CC" = "acc" ; then 335 | CFLAGS="$CFLAGS -vc" 336 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[printf("test");]])],[warning_CFLAGS="-vc"],[]) 337 | fi 338 | ;; 339 | 340 | dnl Unknown, do nothing 341 | *) 342 | warning_CFLAGS="none" 343 | ;; 344 | esac 345 | fi 346 | CFLAGS="$ac_save_CFLAGS" 347 | if test "$warning_CFLAGS" = "none" ; then 348 | AC_MSG_RESULT(none) 349 | else 350 | CFLAGS="$CFLAGS $warning_CFLAGS" 351 | AC_MSG_RESULT($warning_CFLAGS) 352 | fi 353 | 354 | 355 | 356 | 357 | AC_CONFIG_HEADERS([config.h]) 358 | AC_CONFIG_FILES([Makefile img/Makefile]) 359 | AC_OUTPUT 360 | 361 | -------------------------------------------------------------------------------- /display.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "mtr.h" 26 | #include "display.h" 27 | #include "mtr-curses.h" 28 | #include "mtr-gtk.h" 29 | #include "report.h" 30 | #include "select.h" 31 | #include "raw.h" 32 | #include "dns.h" 33 | #include "asn.h" 34 | #ifdef GRAPHCAIRO 35 | #include "graphcairo-mtr.h" 36 | #endif 37 | 38 | extern int DisplayMode; 39 | 40 | #ifdef NO_CURSES 41 | #define mtr_curses_open() 42 | #define mtr_curses_close() 43 | #define mtr_curses_redraw() 44 | #define mtr_curses_keyaction() 45 | #define mtr_curses_clear() 46 | #else 47 | #include "mtr-curses.h" 48 | #endif 49 | 50 | #ifdef NO_GTK 51 | #define gtk_open() 52 | #define gtk_close() 53 | #define gtk_redraw() 54 | #define gtk_keyaction() 0 55 | #define gtk_loop() {fprintf (stderr, "No GTK support. Sorry.\n"); exit (1); } 56 | #else 57 | #include "mtr-gtk.h" 58 | #endif 59 | 60 | #ifdef NO_SPLIT 61 | #define split_open() 62 | #define split_close() 63 | #define split_redraw() 64 | #define split_keyaction() 0 65 | #else 66 | #include "split.h" 67 | #endif 68 | 69 | void display_detect(int *argc, char ***argv) { 70 | DisplayMode = DisplayReport; 71 | 72 | #ifndef NO_CURSES 73 | DisplayMode = DisplayCurses; 74 | #endif 75 | 76 | #ifndef NO_GTK 77 | if(gtk_detect(argc, argv)) { 78 | DisplayMode = DisplayGTK; 79 | } 80 | #endif 81 | } 82 | 83 | 84 | void display_open(void) 85 | { 86 | switch(DisplayMode) { 87 | 88 | case DisplayReport: 89 | report_open(); 90 | break; 91 | case DisplayTXT: 92 | txt_open(); 93 | break; 94 | case DisplayXML: 95 | xml_open(); 96 | break; 97 | case DisplayCSV: 98 | csv_open(); 99 | break; 100 | case DisplayCurses: 101 | mtr_curses_open(); 102 | break; 103 | case DisplaySplit: 104 | split_open(); 105 | break; 106 | case DisplayGTK: 107 | gtk_open(); 108 | break; 109 | #ifdef GRAPHCAIRO 110 | case DisplayGraphCairo: 111 | if (!gc_open()) 112 | exit(1); 113 | break; 114 | #endif 115 | } 116 | } 117 | 118 | 119 | void display_close(time_t now) 120 | { 121 | switch(DisplayMode) { 122 | case DisplayReport: 123 | report_close(); 124 | break; 125 | case DisplayTXT: 126 | txt_close(); 127 | break; 128 | case DisplayXML: 129 | xml_close(); 130 | break; 131 | case DisplayCSV: 132 | csv_close(now); 133 | break; 134 | case DisplayCurses: 135 | mtr_curses_close(); 136 | #ifdef IPINFO 137 | asn_close(); 138 | #endif 139 | break; 140 | case DisplaySplit: 141 | split_close(); 142 | break; 143 | case DisplayGTK: 144 | gtk_close(); 145 | break; 146 | #ifdef GRAPHCAIRO 147 | case DisplayGraphCairo: 148 | gc_close(); 149 | break; 150 | #endif 151 | } 152 | } 153 | 154 | 155 | void display_redraw(void) 156 | { 157 | switch(DisplayMode) { 158 | 159 | case DisplayCurses: 160 | mtr_curses_redraw(); 161 | break; 162 | 163 | case DisplaySplit: 164 | split_redraw(); 165 | break; 166 | 167 | case DisplayGTK: 168 | gtk_redraw(); 169 | break; 170 | 171 | #ifdef GRAPHCAIRO 172 | case DisplayGraphCairo: 173 | gc_redraw(); 174 | break; 175 | #endif 176 | } 177 | } 178 | 179 | 180 | int display_keyaction(void) 181 | { 182 | switch(DisplayMode) { 183 | case DisplayCurses: 184 | return mtr_curses_keyaction(); 185 | 186 | case DisplaySplit: 187 | return split_keyaction(); 188 | 189 | case DisplayGTK: 190 | return gtk_keyaction(); 191 | } 192 | return 0; 193 | } 194 | 195 | 196 | void display_rawping(int host, int msec) 197 | { 198 | switch(DisplayMode) { 199 | case DisplayReport: 200 | case DisplayTXT: 201 | case DisplayXML: 202 | case DisplayCSV: 203 | case DisplaySplit: 204 | case DisplayCurses: 205 | case DisplayGTK: 206 | break; 207 | case DisplayRaw: 208 | raw_rawping (host, msec); 209 | break; 210 | } 211 | } 212 | 213 | 214 | void display_rawhost(int host, ip_t *ip_addr) 215 | { 216 | switch(DisplayMode) { 217 | case DisplayReport: 218 | case DisplayTXT: 219 | case DisplayXML: 220 | case DisplayCSV: 221 | case DisplaySplit: 222 | case DisplayCurses: 223 | case DisplayGTK: 224 | break; 225 | case DisplayRaw: 226 | raw_rawhost (host, ip_addr); 227 | break; 228 | } 229 | } 230 | 231 | 232 | void display_loop(void) 233 | { 234 | switch(DisplayMode) { 235 | case DisplayReport: 236 | case DisplayTXT: 237 | case DisplayXML: 238 | case DisplayCSV: 239 | case DisplaySplit: 240 | case DisplayCurses: 241 | case DisplayRaw: 242 | #ifdef GRAPHCAIRO 243 | case DisplayGraphCairo: 244 | #endif 245 | select_loop(); 246 | break; 247 | case DisplayGTK: 248 | gtk_loop(); 249 | break; 250 | } 251 | } 252 | 253 | void display_clear(void) { 254 | if (DisplayMode == DisplayCurses) 255 | mtr_curses_clear(); 256 | } 257 | -------------------------------------------------------------------------------- /display.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #include 20 | 21 | /* Don't put a trailing comma in enumeration lists. Some compilers 22 | (notably the one on Irix 5.2) do not like that. */ 23 | enum { ActionNone, ActionQuit, ActionReset, ActionDisplay, 24 | ActionClear, ActionPause, ActionResume, ActionMPLS, ActionDNS, 25 | #ifdef IPINFO 26 | ActionII, ActionAS, 27 | #endif 28 | ActionScrollDown, ActionScrollUp }; 29 | enum { DisplayReport, DisplayCurses, DisplayGTK, DisplaySplit, 30 | #ifdef GRAPHCAIRO 31 | DisplayGraphCairo, 32 | #endif 33 | DisplayRaw, DisplayXML, DisplayCSV, DisplayTXT}; 34 | 35 | /* Prototypes for display.c */ 36 | void display_detect(int *argc, char ***argv); 37 | void display_open(void); 38 | void display_close(time_t now); 39 | void display_redraw(void); 40 | void display_rawping(int hostnum, int msec); 41 | void display_rawhost(int hostnum, ip_t *ip_addr); 42 | int display_keyaction(void); 43 | void display_loop(void); 44 | void display_clear(void); 45 | 46 | extern int display_mode; 47 | extern int display_offset; /* only used in text mode */ 48 | -------------------------------------------------------------------------------- /dns.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | /* Prototypes for dns.c */ 24 | 25 | void dns_open(void); 26 | int dns_waitfd(void); 27 | void dns_ack(void); 28 | #ifdef ENABLE_IPV6 29 | int dns_waitfd6(void); 30 | void dns_ack6(void); 31 | #ifdef NEED_RES_STATE_EXT 32 | /* __res_state_ext is missing on many (most?) BSD systems */ 33 | struct __res_state_ext { 34 | union res_sockaddr_union nsaddrs[MAXNS]; 35 | struct sort_list { 36 | int af; 37 | union { 38 | struct in_addr ina; 39 | struct in6_addr in6a; 40 | } addr, mask; 41 | } sort_list[MAXRESOLVSORT]; 42 | char nsuffix[64]; 43 | char nsuffix2[64]; 44 | }; 45 | #endif 46 | #endif 47 | 48 | void dns_events(double *sinterval); 49 | char *dns_lookup(ip_t * address); 50 | char *dns_lookup2(ip_t * address); 51 | struct hostent * dns_forward(const char *name); 52 | char *strlongip(ip_t * ip); 53 | 54 | void addr2ip6arpa( ip_t * ip, char * buf ); 55 | struct hostent *addr2host( const char *addr, int type ); 56 | -------------------------------------------------------------------------------- /getopt/getopt.h: -------------------------------------------------------------------------------- 1 | /* Declarations for getopt. 2 | Copyright (C) 1989-1994,1996-1999,2001,2003,2004 3 | Free Software Foundation, Inc. 4 | This file is part of the GNU C Library. 5 | 6 | The GNU C Library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation version 2. 9 | 10 | The GNU C Library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with the GNU C Library; if not, write to the Free 17 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 18 | 02111-1307 USA. */ 19 | 20 | #ifndef _GETOPT_H 21 | 22 | #ifndef __need_getopt 23 | #define _GETOPT_H 1 24 | #endif 25 | 26 | /* If __GNU_LIBRARY__ is not already defined, either we are being used 27 | standalone, or this is the first header included in the source file. 28 | If we are being used with glibc, we need to include , but 29 | that does not exist if we are standalone. So: if __GNU_LIBRARY__ is 30 | not defined, include , which will pull in for us 31 | if it's from glibc. (Why ctype.h? It's guaranteed to exist and it 32 | doesn't flood the namespace with stuff the way some other headers do.) */ 33 | #if !defined __GNU_LIBRARY__ 34 | # include 35 | #endif 36 | 37 | #ifndef __THROW 38 | # ifndef __GNUC_PREREQ 39 | # define __GNUC_PREREQ(maj, min) (0) 40 | # endif 41 | # if defined __cplusplus && __GNUC_PREREQ (2,8) 42 | # define __THROW throw () 43 | # else 44 | # define __THROW 45 | # endif 46 | #endif 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | /* For communication from `getopt' to the caller. 53 | When `getopt' finds an option that takes an argument, 54 | the argument value is returned here. 55 | Also, when `ordering' is RETURN_IN_ORDER, 56 | each non-option ARGV-element is returned here. */ 57 | 58 | extern char *optarg; 59 | 60 | /* Index in ARGV of the next element to be scanned. 61 | This is used for communication to and from the caller 62 | and for communication between successive calls to `getopt'. 63 | 64 | On entry to `getopt', zero means this is the first call; initialize. 65 | 66 | When `getopt' returns -1, this is the index of the first of the 67 | non-option elements that the caller should itself scan. 68 | 69 | Otherwise, `optind' communicates from one call to the next 70 | how much of ARGV has been scanned so far. */ 71 | 72 | extern int optind; 73 | 74 | /* Callers store zero here to inhibit the error message `getopt' prints 75 | for unrecognized options. */ 76 | 77 | extern int opterr; 78 | 79 | /* Set to an option character which was unrecognized. */ 80 | 81 | extern int optopt; 82 | 83 | #ifndef __need_getopt 84 | /* Describe the long-named options requested by the application. 85 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 86 | of `struct option' terminated by an element containing a name which is 87 | zero. 88 | 89 | The field `has_arg' is: 90 | no_argument (or 0) if the option does not take an argument, 91 | required_argument (or 1) if the option requires an argument, 92 | optional_argument (or 2) if the option takes an optional argument. 93 | 94 | If the field `flag' is not NULL, it points to a variable that is set 95 | to the value given in the field `val' when the option is found, but 96 | left unchanged if the option is not found. 97 | 98 | To have a long-named option do something other than set an `int' to 99 | a compiled-in constant, such as set a value from `optarg', set the 100 | option's `flag' field to zero and its `val' field to a nonzero 101 | value (the equivalent single-letter option character, if there is 102 | one). For long options that have a zero `flag' field, `getopt' 103 | returns the contents of the `val' field. */ 104 | 105 | struct option 106 | { 107 | const char *name; 108 | /* has_arg can't be an enum because some compilers complain about 109 | type mismatches in all the code that assumes it is an int. */ 110 | int has_arg; 111 | int *flag; 112 | int val; 113 | }; 114 | 115 | /* Names for the values of the `has_arg' field of `struct option'. */ 116 | 117 | #define no_argument 0 118 | #define required_argument 1 119 | #define optional_argument 2 120 | #endif /* need getopt */ 121 | 122 | 123 | /* Get definitions and prototypes for functions to process the 124 | arguments in ARGV (ARGC of them, minus the program name) for 125 | options given in OPTS. 126 | 127 | Return the option character from OPTS just read. Return -1 when 128 | there are no more options. For unrecognized options, or options 129 | missing arguments, `optopt' is set to the option letter, and '?' is 130 | returned. 131 | 132 | The OPTS string is a list of characters which are recognized option 133 | letters, optionally followed by colons, specifying that that letter 134 | takes an argument, to be placed in `optarg'. 135 | 136 | If a letter in OPTS is followed by two colons, its argument is 137 | optional. This behavior is specific to the GNU `getopt'. 138 | 139 | The argument `--' causes premature termination of argument 140 | scanning, explicitly telling `getopt' that there are no more 141 | options. 142 | 143 | If OPTS begins with `--', then non-option arguments are treated as 144 | arguments to the option '\0'. This behavior is specific to the GNU 145 | `getopt'. */ 146 | 147 | #ifdef __GNU_LIBRARY__ 148 | /* Many other libraries have conflicting prototypes for getopt, with 149 | differences in the consts, in stdlib.h. To avoid compilation 150 | errors, only prototype getopt for the GNU C library. */ 151 | extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) 152 | __THROW; 153 | #else /* not __GNU_LIBRARY__ */ 154 | extern int getopt (); 155 | #endif /* __GNU_LIBRARY__ */ 156 | 157 | #ifndef __need_getopt 158 | extern int getopt_long (int ___argc, char *const *___argv, 159 | const char *__shortopts, 160 | const struct option *__longopts, int *__longind) 161 | __THROW; 162 | extern int getopt_long_only (int ___argc, char *const *___argv, 163 | const char *__shortopts, 164 | const struct option *__longopts, int *__longind) 165 | __THROW; 166 | 167 | #endif 168 | 169 | #ifdef __cplusplus 170 | } 171 | #endif 172 | 173 | /* Make sure we later can get all the definitions and declarations. */ 174 | #undef __need_getopt 175 | 176 | #endif /* getopt.h */ 177 | -------------------------------------------------------------------------------- /getopt/getopt1.c: -------------------------------------------------------------------------------- 1 | /* getopt_long and getopt_long_only entry points for GNU getopt. 2 | Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994 3 | Free Software Foundation, Inc. 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ 17 | 18 | #ifdef HAVE_CONFIG_H 19 | #include "config.h" 20 | #endif 21 | 22 | #include "getopt.h" 23 | 24 | #if !defined (__STDC__) || !__STDC__ 25 | /* This is a separate conditional since some stdc systems 26 | reject `defined (const)'. */ 27 | #ifndef const 28 | #define const 29 | #endif 30 | #endif 31 | 32 | #include 33 | 34 | /* Comment out all this code if we are using the GNU C Library, and are not 35 | actually compiling the library itself. This code is part of the GNU C 36 | Library, but also included in many other GNU distributions. Compiling 37 | and linking in this code is a waste when using the GNU C library 38 | (especially if it is a shared library). Rather than having every GNU 39 | program understand `configure --with-gnu-libc' and omit the object files, 40 | it is simpler to just do this in the source for each such file. */ 41 | 42 | #if defined (_LIBC) || !defined (__GNU_LIBRARY__) 43 | 44 | 45 | /* This needs to come after some library #include 46 | to get __GNU_LIBRARY__ defined. */ 47 | #ifdef __GNU_LIBRARY__ 48 | #include 49 | #else 50 | char *getenv (); 51 | #endif 52 | 53 | #ifndef NULL 54 | #define NULL 0 55 | #endif 56 | 57 | int 58 | getopt_long (argc, argv, options, long_options, opt_index) 59 | int argc; 60 | char *const *argv; 61 | const char *options; 62 | const struct option *long_options; 63 | int *opt_index; 64 | { 65 | return _getopt_internal (argc, argv, options, long_options, opt_index, 0); 66 | } 67 | 68 | /* Like getopt_long, but '-' as well as '--' can indicate a long option. 69 | If an option that starts with '-' (not '--') doesn't match a long option, 70 | but does match a short option, it is parsed as a short option 71 | instead. */ 72 | 73 | int 74 | getopt_long_only (argc, argv, options, long_options, opt_index) 75 | int argc; 76 | char *const *argv; 77 | const char *options; 78 | const struct option *long_options; 79 | int *opt_index; 80 | { 81 | return _getopt_internal (argc, argv, options, long_options, opt_index, 1); 82 | } 83 | 84 | 85 | #endif /* _LIBC or not __GNU_LIBRARY__. */ 86 | 87 | #ifdef TEST 88 | 89 | #include 90 | 91 | int 92 | main (argc, argv) 93 | int argc; 94 | char **argv; 95 | { 96 | int c; 97 | int digit_optind = 0; 98 | 99 | while (1) 100 | { 101 | int this_option_optind = optind ? optind : 1; 102 | int option_index = 0; 103 | static struct option long_options[] = 104 | { 105 | {"add", 1, 0, 0}, 106 | {"append", 0, 0, 0}, 107 | {"delete", 1, 0, 0}, 108 | {"verbose", 0, 0, 0}, 109 | {"create", 0, 0, 0}, 110 | {"file", 1, 0, 0}, 111 | {0, 0, 0, 0} 112 | }; 113 | 114 | c = getopt_long (argc, argv, "abc:d:0123456789", 115 | long_options, &option_index); 116 | if (c == EOF) 117 | break; 118 | 119 | switch (c) 120 | { 121 | case 0: 122 | printf ("option %s", long_options[option_index].name); 123 | if (optarg) 124 | printf (" with arg %s", optarg); 125 | printf ("\n"); 126 | break; 127 | 128 | case '0': 129 | case '1': 130 | case '2': 131 | case '3': 132 | case '4': 133 | case '5': 134 | case '6': 135 | case '7': 136 | case '8': 137 | case '9': 138 | if (digit_optind != 0 && digit_optind != this_option_optind) 139 | printf ("digits occur in two different argv-elements.\n"); 140 | digit_optind = this_option_optind; 141 | printf ("option %c\n", c); 142 | break; 143 | 144 | case 'a': 145 | printf ("option a\n"); 146 | break; 147 | 148 | case 'b': 149 | printf ("option b\n"); 150 | break; 151 | 152 | case 'c': 153 | printf ("option c with value `%s'\n", optarg); 154 | break; 155 | 156 | case 'd': 157 | printf ("option d with value `%s'\n", optarg); 158 | break; 159 | 160 | case '?': 161 | break; 162 | 163 | default: 164 | printf ("?? getopt returned character code 0%o ??\n", c); 165 | } 166 | } 167 | 168 | if (optind < argc) 169 | { 170 | printf ("non-option ARGV-elements: "); 171 | while (optind < argc) 172 | printf ("%s ", argv[optind++]); 173 | printf ("\n"); 174 | } 175 | 176 | exit (0); 177 | } 178 | 179 | #endif /* TEST */ 180 | -------------------------------------------------------------------------------- /graphcairo/graphcairo-backend.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHCAIRO_BACKEND_H 2 | #define GRAPHCAIRO_BACKEND_H 3 | 4 | #include 5 | 6 | #if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 10, 0) 7 | typedef struct { 8 | int x, y; 9 | int width, height; 10 | } cairo_rectangle_int_t; 11 | #endif 12 | 13 | typedef void (*frontend_resize_t)(int, int, int); 14 | int backend_create_window(cairo_rectangle_int_t *rectangle, frontend_resize_t frontend_resize_func); 15 | void backend_destroy_window(void); 16 | cairo_surface_t* backend_create_surface(int width, int height); 17 | int backend_dispatch_event(void); 18 | void backend_flush(void); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /graphcairo/graphcairo-mtr.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "config.h" 10 | 11 | #ifdef UNICODE 12 | #ifdef HAVE_WCHAR_H 13 | #include 14 | #endif 15 | #endif 16 | 17 | #include "mtr.h" 18 | #include "mtr-curses.h" 19 | #include "net.h" 20 | #include "dns.h" 21 | #include "asn.h" 22 | #include "display.h" 23 | #include "graphcairo.h" 24 | 25 | #define GC_ARGS_SEP ',' 26 | #define GC_ARGS_MAX 5 27 | 28 | #ifdef UNICODE 29 | #define U_FACTOR sizeof(wchar_t) 30 | #else 31 | #define U_FACTOR 1 32 | #endif 33 | 34 | #ifdef IPINFO 35 | #define HOSTSTAT_LEN (3 * STARTSTAT + U_FACTOR * SAVED_PINGS) // hostinfo + statistics 36 | #else 37 | #define HOSTSTAT_LEN (STARTSTAT + U_FACTOR * SAVED_PINGS) // hostname + statistics 38 | #endif 39 | 40 | #define NUMHOSTS 10 // net.c static numhosts = 10 41 | 42 | extern int af; // mtr.c 43 | extern int mtrtype; 44 | extern int maxTTL; 45 | extern float WaitTime; 46 | extern int display_mode_max; 47 | 48 | static int timeout; 49 | static struct timeval lasttime; 50 | 51 | static int paused; 52 | static cr_params_t params; 53 | #define ARG_GRAPH_TYPE 0 54 | #define ARG_PERIOD 1 55 | #define ARG_LEGEND 2 56 | #define ARG_MULTIPATH 3 57 | #define ARG_JITTER_GRAPH 4 58 | 59 | static int args[GC_ARGS_MAX]; 60 | static int *data; 61 | static int num_pings; 62 | static int curses_cols; 63 | static int hostinfo_max; 64 | static char buf[HOSTSTAT_LEN]; 65 | 66 | enum { 67 | LEGEND_HEADER_STATIC, 68 | LEGEND_HEADER, 69 | LEGEND_FOOTER 70 | }; 71 | #define LEGEND_HD_NO 3 72 | static char legend_hd[LEGEND_HD_NO][HOSTSTAT_LEN]; 73 | 74 | int gc_open(void) { 75 | if ((data = malloc(maxTTL * sizeof(int)))) 76 | memset(data, -1, maxTTL * sizeof(int)); 77 | else { 78 | fprintf(stderr, "gc_open: malloc() failed\n"); 79 | return 0; 80 | } 81 | 82 | timeout = POS_ROUND(WaitTime * USECONDS); 83 | gettimeofday(&lasttime, NULL); 84 | 85 | params.graph_type = (args[ARG_GRAPH_TYPE] > 0) ? args[ARG_GRAPH_TYPE] : 0; 86 | params.period = (args[ARG_PERIOD] > 0) ? args[ARG_PERIOD] : 0; 87 | params.enable_legend = args[ARG_LEGEND] ? 1 : 0; 88 | params.enable_multipath = (args[ARG_MULTIPATH] > 0) ? 1 : 0; 89 | params.jitter_graph = (args[ARG_JITTER_GRAPH] > 0) ? 1 : 0; 90 | params.cols_max = SAVED_PINGS; 91 | params.path_max = MAXPATH; 92 | params.label_max = MAXLABELS; 93 | 94 | if (!cr_open(¶ms)) 95 | return 0; 96 | 97 | if (params.enable_legend) { 98 | if (params.jitter_graph == 1) 99 | strcpy(fld_active, "DR AGJMXI"); 100 | mtr_curses_data_fields(legend_hd[LEGEND_HEADER_STATIC]); 101 | curses_cols = cr_recalc(hostinfo_max); 102 | mtr_curses_init(); 103 | } 104 | 105 | return 1; 106 | } 107 | 108 | void gc_close(void) { 109 | free(data); 110 | cr_close(); 111 | } 112 | 113 | void gc_parsearg(char* arg) { 114 | int i = 0; 115 | if (arg) { 116 | char *n, *p, *h = strdup(arg); 117 | for (p = h; (n = strchr(p, GC_ARGS_SEP)) && (i < GC_ARGS_MAX); i++, p = n) { 118 | *n++ = 0; 119 | args[i] = (*p) ? atoi(p) : -1; 120 | } 121 | if (p && (i < GC_ARGS_MAX)) 122 | args[i++] = (*p) ? atoi(p) : -1; 123 | free(h); 124 | } 125 | 126 | int j; 127 | for (j = i; j < GC_ARGS_MAX; j++) 128 | args[j] = -1; 129 | } 130 | 131 | void fill_hostinfo(int at, ip_t *addr) { 132 | int l, len = 0; 133 | char *p = buf; 134 | int sz; 135 | #ifdef IPINFO 136 | if (enable_ipinfo) { 137 | sz = 2 * STARTSTAT; 138 | l = snprintf(p, sz, "%s", fmt_ipinfo(addr)); 139 | if (l < 0) 140 | sz = 0; 141 | else if (l < sz) 142 | sz = l; 143 | else 144 | sz -= 1; 145 | len += sz; 146 | p += sz; 147 | } 148 | #endif 149 | sz = STARTSTAT; 150 | char *name = dns_lookup(addr); 151 | if (name) { 152 | if (show_ips) 153 | l = snprintf(p, sz, "%s (%s)", name, strlongip(addr)); 154 | else 155 | l = snprintf(p, sz, "%s", name); 156 | } else 157 | l = snprintf(p, sz, "%s", strlongip(addr)); 158 | 159 | if (l < 0) 160 | sz = 0; 161 | else if (l < sz) 162 | sz = l; 163 | else 164 | sz -= 1; 165 | len += sz; 166 | 167 | if ((at + 1) >= display_offset) 168 | if (len > hostinfo_max) 169 | hostinfo_max = len; 170 | } 171 | 172 | void pr_lastd(void) { 173 | if (display_mode) 174 | sprintf(legend_hd[LEGEND_HEADER], "Last %d pings", curses_cols); 175 | } 176 | 177 | void gc_keyaction(int c) { 178 | if (!c) 179 | return; 180 | 181 | if (c == ACTION_RESIZE) { 182 | if (params.enable_legend) { 183 | curses_cols = cr_recalc(hostinfo_max); 184 | pr_lastd(); 185 | } 186 | return; 187 | } 188 | 189 | if (params.enable_legend) { 190 | switch (c) { 191 | case '+': { // ScrollDown 192 | int hops = net_max() - net_min(); 193 | display_offset += 5; 194 | if (display_offset >= hops) 195 | display_offset = hops - 1; 196 | hostinfo_max = 0; 197 | GCDEBUG_MSG(("display_offset=%d\n", display_offset)); 198 | } break; 199 | case '-': { // ScrollUp 200 | int rest = display_offset % 5; 201 | if (rest) 202 | display_offset -= rest; 203 | else 204 | display_offset -= 5; 205 | if (display_offset < 0) 206 | display_offset = 0; 207 | hostinfo_max = 0; 208 | GCDEBUG_MSG(("display_offset=%d\n", display_offset)); 209 | } break; 210 | } 211 | switch (tolower(c)) { 212 | case 'd': // Display 213 | display_mode = (display_mode + 1) % display_mode_max; 214 | if (display_mode) 215 | curses_cols = cr_recalc(hostinfo_max); 216 | pr_lastd(); 217 | GCDEBUG_MSG(("display_mode=%d\n", display_mode)); 218 | break; 219 | case 'e': // MPLS 220 | enablempls = !enablempls; 221 | GCDEBUG_MSG(("enable_mpls=%d\n", enablempls)); 222 | break; 223 | case 'j': 224 | if (index(fld_active, 'N')) 225 | strcpy(fld_active, "DR AGJMXI"); 226 | else 227 | strcpy(fld_active, "LS NABWV"); 228 | mtr_curses_data_fields(legend_hd[LEGEND_HEADER_STATIC]); 229 | GCDEBUG_MSG(("toggle latency/jitter stats\n")); 230 | break; 231 | case 'n': // DNS 232 | use_dns = !use_dns; 233 | hostinfo_max = 0; 234 | GCDEBUG_MSG(("use_dns=%d\n", use_dns)); 235 | break; 236 | #ifdef IPINFO 237 | case 'y': // IP Info 238 | ii_action(0); 239 | hostinfo_max = 0; 240 | GCDEBUG_MSG(("switching ip info\n")); 241 | break; 242 | case 'z': // ASN 243 | ii_action(1); 244 | hostinfo_max = 0; 245 | GCDEBUG_MSG(("toggle asn info\n")); 246 | break; 247 | #endif 248 | } 249 | } 250 | 251 | switch (c) { 252 | case 'q': // Quit 253 | gc_close(); 254 | GCDEBUG_MSG(("bye-bye\n")); 255 | exit(0); 256 | break; 257 | case ' ': // Resume 258 | paused = 0; 259 | cr_net_reset(1); 260 | GCDEBUG_MSG(("...resume\n")); 261 | break; 262 | } 263 | switch (tolower(c)) { 264 | case 'p': // Pause 265 | paused = 1; 266 | GCDEBUG_MSG(("pause...\n")); 267 | break; 268 | case 'r': // Reset 269 | net_reset(); 270 | cr_net_reset(0); 271 | num_pings = 0; 272 | GCDEBUG_MSG(("net reset\n")); 273 | break; 274 | case 't': // TCP and ICMP ECHO 275 | switch (mtrtype) { 276 | case IPPROTO_ICMP: 277 | case IPPROTO_UDP: 278 | mtrtype = IPPROTO_TCP; 279 | GCDEBUG_MSG(("tcp_syn packets\n")); 280 | break; 281 | case IPPROTO_TCP: 282 | mtrtype = IPPROTO_ICMP; 283 | GCDEBUG_MSG(("icmp_echo packets\n")); 284 | break; 285 | } 286 | break; 287 | case 'u': // UDP and ICMP ECHO 288 | switch (mtrtype) { 289 | case IPPROTO_ICMP: 290 | case IPPROTO_TCP: 291 | GCDEBUG_MSG(("udp datagrams\n")); 292 | mtrtype = IPPROTO_UDP; 293 | break; 294 | case IPPROTO_UDP: 295 | mtrtype = IPPROTO_ICMP; 296 | GCDEBUG_MSG(("icmp_echo packets\n")); 297 | break; 298 | } 299 | break; 300 | } 301 | } 302 | 303 | void gc_print_mpls(int i, int d, struct mplslen *mpls) { 304 | if (mpls) { 305 | int j; 306 | for (j = 0; (j < mpls->labels) && (j < MAXLABELS); j++) { 307 | sprintf(buf, "[MPLS: Lbl %lu Exp %u S %u TTL %u]", 308 | mpls->label[j], mpls->exp[j], mpls->s[j], mpls->ttl[j]); 309 | cr_print_host(i, d, buf, NULL); 310 | } 311 | } 312 | } 313 | 314 | void gc_redraw(void) { 315 | gc_keyaction(cr_dispatch_event()); 316 | if (paused) 317 | return; 318 | 319 | int i, at; 320 | int min = net_min(); 321 | int max = net_max(); 322 | int hops = max - min /* + 1 */; 323 | if (!hops) 324 | hops++; 325 | 326 | cr_set_hops(hops, min); 327 | 328 | struct timeval now; 329 | gettimeofday(&now, NULL); 330 | int dt = (now.tv_sec - lasttime.tv_sec) * USECONDS + (now.tv_usec - lasttime.tv_usec); 331 | lasttime = now; 332 | 333 | if (dt < timeout) { 334 | int pings = net_xmit(min); 335 | for (at = min + 1; at < max; at++) 336 | if (net_xmit(at) != pings) 337 | return; 338 | if (pings > num_pings) 339 | num_pings = pings; 340 | else 341 | return; 342 | } 343 | 344 | if (params.enable_legend) { 345 | static int hi_max; 346 | if (!hostinfo_max) 347 | hi_max = 0; 348 | if (hostinfo_max > hi_max) { 349 | hi_max = hostinfo_max; 350 | curses_cols = cr_recalc(hostinfo_max); 351 | pr_lastd(); 352 | } 353 | cr_init_legend(); 354 | cr_print_legend_header(display_mode ? legend_hd[LEGEND_HEADER] : legend_hd[LEGEND_HEADER_STATIC]); 355 | } 356 | 357 | for (i = 0, at = min; i < hops; i++, at++) { 358 | ip_t *addr = net_addr(at); 359 | 360 | if (addrcmp((void *)addr, (void *)&unspec_addr, af) != 0) { 361 | int *saved = net_saved_pings(at); 362 | int saved_ndx = SAVED_PINGS - 2; // waittime ago 363 | if (params.jitter_graph) { 364 | // jitter, defined as "tN - tN-1" (net.c) 365 | if ((saved[saved_ndx] < 0) || (saved[saved_ndx - 1] < 0)) // unsent, unknown, etc. 366 | data[i] = -1; 367 | else { 368 | int saved_jttr = saved[saved_ndx] - saved[saved_ndx - 1]; 369 | data[i] = (saved_jttr < 0) ? -saved_jttr : saved_jttr; 370 | } 371 | } else 372 | data[i] = (saved[saved_ndx] >= 0) ? saved[saved_ndx] : -1; 373 | 374 | if (params.enable_legend) { 375 | // line+hop 376 | cr_print_hop(i); 377 | 378 | // hostinfo 379 | fill_hostinfo(at, addr); 380 | 381 | char *stat = buf + strlen(buf) + 1; 382 | // statistics 383 | if (display_mode) { 384 | mtr_gen_scale_gc(); 385 | char *pos = stat; 386 | int j; 387 | #ifdef UNICODE 388 | if (display_mode == 3) { 389 | for (j = SAVED_PINGS - curses_cols; j < SAVED_PINGS; j++) { 390 | *(wchar_t*)pos = mtr_curses_saved_wch(saved[j]); 391 | pos += sizeof(wchar_t); 392 | } 393 | *(wchar_t*)pos = L'\0'; 394 | } else 395 | #endif 396 | { 397 | for (j = SAVED_PINGS - curses_cols; j < SAVED_PINGS; j++) 398 | *pos++ = mtr_curses_saved_ch(saved[j]); 399 | *pos = 0; 400 | } 401 | } else 402 | mtr_fill_data(at, stat); 403 | cr_print_host(i, data[i], buf, stat); 404 | 405 | // mpls 406 | if (enablempls) 407 | gc_print_mpls(i, data[i], net_mpls(at)); 408 | 409 | // multipath 410 | if (params.enable_multipath) { 411 | int j; 412 | for (j = 0; j < MAXPATH; j++) { 413 | ip_t *addrs = net_addrs(at, j); 414 | if (addrcmp((void *)addrs, (void *)addr, af) == 0) 415 | continue; 416 | if (addrcmp((void *)addrs, (void *)&unspec_addr, af) == 0) 417 | break; 418 | fill_hostinfo(at, addrs); 419 | cr_print_host(i, data[i], buf, NULL); 420 | if (enablempls) // multipath+mpls 421 | gc_print_mpls(i, data[i], net_mplss(at, j)); 422 | } 423 | } 424 | } 425 | } else // empty hop 426 | if (params.enable_legend) { 427 | cr_print_hop(i); 428 | cr_print_host(i, 0, NULL, NULL); 429 | } 430 | } 431 | 432 | if (params.enable_legend) 433 | if (display_mode) { 434 | mtr_curses_scale_desc(legend_hd[LEGEND_FOOTER]); 435 | cr_print_legend_footer(legend_hd[LEGEND_FOOTER]); 436 | } 437 | 438 | cr_redraw(data); 439 | 440 | if (hops) 441 | timeout = POS_ROUND(((WaitTime * hops) / NUMHOSTS) * USECONDS); 442 | } 443 | 444 | -------------------------------------------------------------------------------- /graphcairo/graphcairo-mtr.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHCAIRO_MTR_H 2 | #define GRAPHCAIRO_MTR_H 3 | 4 | int gc_open(void); 5 | void gc_close(void); 6 | void gc_parsearg(char* arg); 7 | void gc_redraw(void); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /graphcairo/graphcairo-xcb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define XK_LATIN1 7 | #define XK_MISCELLANY 8 | #include 9 | 10 | #include 11 | #include "graphcairo-backend.h" 12 | 13 | static xcb_connection_t *connection; 14 | static xcb_window_t window; 15 | static xcb_screen_t *screen; 16 | static xcb_visualtype_t *visual_type; 17 | static xcb_atom_t delete_window_atom; 18 | static frontend_resize_t frontend_resize; 19 | static int shiftkey_pressed; 20 | 21 | void root_visual_type(void) { 22 | xcb_depth_iterator_t depth_iter; 23 | for (depth_iter = xcb_screen_allowed_depths_iterator(screen); 24 | depth_iter.rem; xcb_depth_next(&depth_iter)) { 25 | xcb_visualtype_iterator_t visual_iter; 26 | for (visual_iter = xcb_depth_visuals_iterator(depth_iter.data); 27 | visual_iter.rem; xcb_visualtype_next(&visual_iter)) 28 | if (screen->root_visual == visual_iter.data->visual_id) { 29 | visual_type = visual_iter.data; 30 | return; 31 | } 32 | } 33 | visual_type = NULL; 34 | } 35 | 36 | cairo_surface_t* backend_create_surface(int width, int height) { 37 | return cairo_xcb_surface_create(connection, window, visual_type, width, height); 38 | } 39 | 40 | int backend_create_window(cairo_rectangle_int_t *rectangle, frontend_resize_t frontend_resize_func) { 41 | frontend_resize = frontend_resize_func; 42 | 43 | int screen_no; 44 | connection = xcb_connect(NULL, &screen_no); 45 | if (xcb_connection_has_error(connection)) { 46 | fprintf(stderr, "xcb backend_create_window(): can't connect to an X server\n"); 47 | return 0; 48 | } 49 | 50 | const xcb_setup_t *setup = xcb_get_setup(connection); 51 | screen = NULL; 52 | xcb_screen_iterator_t screen_iter; 53 | for (screen_iter = xcb_setup_roots_iterator(setup); screen_iter.rem != 0; 54 | --screen_no, xcb_screen_next(&screen_iter)) 55 | if (screen_no == 0) { 56 | screen = screen_iter.data; 57 | break; 58 | } 59 | 60 | window = xcb_generate_id(connection); 61 | uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; 62 | uint32_t values[2]; 63 | values[0] = screen->white_pixel; 64 | values[1] = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE; 65 | 66 | xcb_void_cookie_t cookie_window = xcb_create_window_checked(connection, XCB_COPY_FROM_PARENT, 67 | window, screen->root, rectangle->x, rectangle->y, rectangle->width, rectangle->height, 0, 68 | XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, mask, values); 69 | xcb_void_cookie_t cookie_map = xcb_map_window_checked(connection, window); 70 | 71 | xcb_generic_error_t *error = xcb_request_check(connection, cookie_window); 72 | if (error) { 73 | fprintf(stderr, "xcb backend_create_window(): can't create window : %d\n", error->error_code); 74 | free(error); 75 | xcb_destroy_window(connection, window); 76 | xcb_disconnect(connection); 77 | return 0; 78 | } 79 | error = xcb_request_check(connection, cookie_map); 80 | if (error) { 81 | fprintf(stderr, "xcb backend_create_window(): can't map window : %d\n", error->error_code); 82 | free(error); 83 | xcb_destroy_window(connection, window); 84 | xcb_disconnect(connection); 85 | return 0; 86 | } 87 | 88 | xcb_intern_atom_cookie_t cookie = xcb_intern_atom(connection, 1, 12, "WM_PROTOCOLS"); 89 | xcb_intern_atom_reply_t* reply = xcb_intern_atom_reply(connection, cookie, 0); 90 | if (reply) { 91 | xcb_intern_atom_cookie_t cookie2 = xcb_intern_atom(connection, 0, 16, "WM_DELETE_WINDOW"); 92 | xcb_intern_atom_reply_t* reply2 = xcb_intern_atom_reply(connection, cookie2, 0); 93 | if (reply2) { 94 | xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window, (*reply).atom, 4, 32, 1, &(*reply2).atom); 95 | delete_window_atom = (*reply2).atom; 96 | free(reply2); 97 | } 98 | free(reply); 99 | } 100 | 101 | xcb_flush(connection); 102 | if (xcb_connection_has_error(connection)) { 103 | fprintf(stderr, "xcb backend_create_window() failed: xcb_connection_has_error()\n"); 104 | return 0; 105 | } 106 | 107 | while (1) { 108 | xcb_generic_event_t *ev = xcb_wait_for_event(connection); 109 | if ((ev->response_type & ~0x80) == XCB_EXPOSE) { 110 | root_visual_type(); 111 | break; 112 | } 113 | } 114 | 115 | return 1; 116 | } 117 | 118 | void backend_destroy_window(void) { 119 | xcb_destroy_window(connection, window); 120 | xcb_disconnect(connection); 121 | } 122 | 123 | void backend_flush(void) { 124 | xcb_flush(connection); 125 | } 126 | 127 | int keysym_to_char(xcb_keysym_t keysym) { 128 | int c = 0; 129 | // [a-zA-Z\-\+ ] 130 | if ((keysym >= XK_a) && (keysym <= XK_z)) 131 | c = (int)'a' + (keysym - XK_a); 132 | else if ((keysym >= XK_A) && (keysym <= XK_Z)) 133 | c = (int)'A' + (keysym - XK_A); 134 | else if (keysym == XK_space) 135 | c = (int)' '; 136 | else if ((keysym == XK_plus) || (keysym == XK_KP_Add)) 137 | c = (int)'+'; 138 | else if ((keysym == XK_minus) || (keysym == XK_KP_Subtract)) 139 | c = (int)'-'; 140 | return c; 141 | } 142 | 143 | int keycode_to_char(xcb_key_release_event_t *ev) { 144 | static xcb_key_symbols_t *key_symbols; 145 | if (!key_symbols) 146 | key_symbols = xcb_key_symbols_alloc(connection); 147 | 148 | xcb_keysym_t keysym = xcb_key_symbols_get_keysym(key_symbols, ev->detail, 0); 149 | xcb_keysym_t keymod = xcb_key_symbols_get_keysym(key_symbols, ev->detail, ev->state & XCB_MOD_MASK_SHIFT); 150 | 151 | int typ = ev->response_type & ~0x80; 152 | if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) || 153 | (keymod == XK_Shift_L) || (keymod == XK_Shift_R)) 154 | shiftkey_pressed = (typ == XCB_KEY_PRESS) ? 1 : 0; 155 | #if 0 156 | printf("keysym=0x%x, keymod=0x%x, shiftkey=%d, type=%d\n", 157 | (unsigned int)keysym, (unsigned int)keymod, shiftkey_pressed, typ); 158 | #endif 159 | 160 | int c = 0; 161 | if (typ == XCB_KEY_RELEASE) 162 | if (!(c = keysym_to_char(keysym))) 163 | c = keysym_to_char(keymod); 164 | return c; 165 | } 166 | 167 | int backend_dispatch_event(void) { 168 | int key = 0; 169 | xcb_generic_event_t *ev; 170 | while ((ev = xcb_poll_for_event(connection))) { 171 | switch (ev->response_type & ~0x80) { 172 | case XCB_CONFIGURE_NOTIFY: 173 | frontend_resize(((xcb_configure_notify_event_t*)ev)->width, 174 | ((xcb_configure_notify_event_t*)ev)->height, shiftkey_pressed); 175 | break; 176 | case XCB_EXPOSE: 177 | break; 178 | case XCB_CLIENT_MESSAGE: 179 | if ((*(xcb_client_message_event_t*)ev).data.data32[0] == delete_window_atom) 180 | key = 'q'; 181 | break; 182 | case XCB_KEY_PRESS: 183 | case XCB_KEY_RELEASE: 184 | key = keycode_to_char((xcb_key_release_event_t *)ev); 185 | break; 186 | default: 187 | //printf("got event: %d\n", ev->response_type & ~0x80); 188 | break; 189 | } 190 | free(ev); 191 | } 192 | return key; 193 | } 194 | 195 | -------------------------------------------------------------------------------- /graphcairo/graphcairo-xcb.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHCAIRO_XCB_H 2 | #define GRAPHCAIRO_XCB_H 3 | 4 | #include 5 | 6 | typedef void (*frontend_resize_t)(int, int, int); 7 | int backend_create_window(int width, int height, 8 | frontend_resize_t frontend_resize_func); 9 | void backend_destroy_window(void); 10 | cairo_surface_t* backend_create_surface(int width, int height); 11 | int backend_dispatch_event(void); 12 | void backend_flush(void); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /graphcairo/graphcairo-xlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define XK_LATIN1 6 | #define XK_MISCELLANY 7 | #include 8 | 9 | #include 10 | #include "graphcairo-backend.h" 11 | 12 | static Display *display; 13 | static Window window; 14 | static int screen; 15 | static Atom delete_window_atom; 16 | static frontend_resize_t frontend_resize; 17 | static int shiftkey_pressed; 18 | 19 | cairo_surface_t* backend_create_surface(int width, int height) { 20 | return cairo_xlib_surface_create(display, window, DefaultVisual(display, screen), width, height); 21 | } 22 | 23 | int backend_create_window(cairo_rectangle_int_t *rectangle, frontend_resize_t frontend_resize_func) { 24 | frontend_resize = frontend_resize_func; 25 | display = XOpenDisplay(NULL); 26 | if (!display) { 27 | fprintf(stderr, "xlib backend_create_window(): can't open display\n"); 28 | return 0; 29 | } 30 | screen = DefaultScreen(display); 31 | window = XCreateSimpleWindow(display, RootWindow(display, screen), 32 | rectangle->x, rectangle->y, rectangle->width, rectangle->height, 0, 33 | BlackPixel(display, screen), WhitePixel(display, screen)); 34 | XSelectInput(display, window, 35 | ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask); 36 | XMapWindow(display, window); 37 | delete_window_atom = XInternAtom(display, "WM_DELETE_WINDOW", False); 38 | XSetWMProtocols(display, window, &delete_window_atom, 1); 39 | XFlush(display); 40 | while (1) { 41 | XEvent ev; 42 | XNextEvent(display, &ev); 43 | if (ev.type == Expose) 44 | break; 45 | } 46 | return 1; 47 | } 48 | 49 | void backend_destroy_window(void) { 50 | XDestroyWindow(display, window); 51 | XCloseDisplay(display); 52 | } 53 | 54 | void backend_flush(void) { 55 | XFlush(display); 56 | } 57 | 58 | int keysym_to_char(KeySym keysym) { 59 | int c = 0; 60 | // [a-zA-Z\-\+ ] 61 | if ((keysym >= XK_a) && (keysym <= XK_z)) 62 | c = (int)'a' + (keysym - XK_a); 63 | else if ((keysym >= XK_A) && (keysym <= XK_Z)) 64 | c = (int)'A' + (keysym - XK_A); 65 | else if (keysym == XK_space) 66 | c = (int)' '; 67 | else if (keysym == XK_KP_Add) 68 | c = (int)'+'; 69 | else if ((keysym == XK_minus) || (keysym == XK_KP_Subtract)) 70 | c = (int)'-'; 71 | return c; 72 | } 73 | 74 | int keycode_to_char(XKeyEvent *ev) { 75 | int keysyms_per_keycode_return; 76 | KeySym *p = XGetKeyboardMapping(display, ev->keycode, 2, &keysyms_per_keycode_return); 77 | KeySym keysym = 0; 78 | KeySym keymod = 0; 79 | if (p) { 80 | keysym = *p; 81 | keymod = *(p + 1); 82 | } 83 | XFree(p); 84 | 85 | if ((keysym == XK_Shift_L) || (keysym == XK_Shift_R) || 86 | (keymod == XK_Shift_L) || (keymod == XK_Shift_R)) 87 | shiftkey_pressed = (ev->type == KeyPress) ? 1 : 0; 88 | #if 0 89 | printf("keysym=0x%x, keymod=0x%x, shiftkey=%d, type=%d\n", 90 | (unsigned int)keysym, (unsigned int)keymod, shiftkey_pressed, ev->type); 91 | #endif 92 | 93 | int c = 0; 94 | if (ev->type == KeyRelease) { 95 | if ((keymod == XK_plus) && shiftkey_pressed) 96 | return '+'; 97 | c = keysym_to_char(keysym); 98 | } 99 | return c; 100 | } 101 | 102 | int backend_dispatch_event(void) { 103 | int key = 0; 104 | XEvent event; 105 | XEvent *ev = &event; 106 | while (XPending(display)) { 107 | XNextEvent(display, ev); 108 | switch (event.type) { 109 | case ConfigureNotify: 110 | frontend_resize(((XConfigureEvent*)ev)->width, 111 | ((XConfigureEvent*)ev)->height, shiftkey_pressed); 112 | break; 113 | case Expose: 114 | break; 115 | case ClientMessage: 116 | if ((Atom)event.xclient.data.l[0] == delete_window_atom) 117 | key = 'q'; 118 | break; 119 | case KeyPress: 120 | case KeyRelease: 121 | key = keycode_to_char((XKeyEvent*)ev); 122 | break; 123 | default: 124 | //printf("got event: %d\n", ev->response_type & ~0x80); 125 | break; 126 | } 127 | } 128 | return key; 129 | } 130 | 131 | -------------------------------------------------------------------------------- /graphcairo/graphcairo.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHCAIRO_H 2 | #define GRAPHCAIRO_H 3 | 4 | /**/ 5 | #ifndef GCDEBUG 6 | #define GCDEBUG 7 | #endif 8 | /**/ 9 | 10 | #ifdef GCDEBUG 11 | #define GCDEBUG_MSG(x) printf x 12 | #else 13 | #define GCDEBUG_MSG(x) 14 | #endif 15 | 16 | //#define ROUND(x) ((x)>=0?(int)((x)+0.5):(int)((x)-0.5)) 17 | #define POS_ROUND(x) ((int)((x)+0.5)) 18 | #define USECONDS 1000000 19 | #define ACTION_RESIZE -1 20 | 21 | typedef struct { 22 | int graph_type; 23 | int period; 24 | int enable_legend; 25 | int enable_multipath; 26 | int jitter_graph; 27 | int cols_max; 28 | int path_max; 29 | int label_max; 30 | } cr_params_t; 31 | 32 | int cr_open(cr_params_t *cr_params); 33 | void cr_close(void); 34 | int cr_dispatch_event(void); 35 | void cr_redraw(int *data); 36 | void cr_set_hops(int curr_hops, int min_hop); 37 | void cr_net_reset(int paused); 38 | 39 | int cr_recalc(int hostinfo_max); 40 | void cr_init_legend(void); 41 | void cr_print_legend_header(char *header); 42 | void cr_print_legend_footer(char *footer); 43 | void cr_print_hop(int at); 44 | void cr_print_host(int at, int data, char *host, char *stat); 45 | int cr_display_offset(void); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /img/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = mtr_icon.xpm 2 | -------------------------------------------------------------------------------- /img/mtr_icon.xpm: -------------------------------------------------------------------------------- 1 | /* XPM */ 2 | static char * mtr_icon[] = { 3 | "48 48 131 2", 4 | " c #000000", 5 | ". c #020204", 6 | "+ c #3E7E3C", 7 | "@ c #62BA64", 8 | "# c #4E9E4C", 9 | "$ c #628664", 10 | "% c #6EDA6C", 11 | "& c #7A9E7C", 12 | "* c #468E44", 13 | "= c #6ACA6C", 14 | "- c #224224", 15 | "; c #56AE54", 16 | "> c #326234", 17 | ", c #567E54", 18 | "' c #7ABA7C", 19 | ") c #3A723C", 20 | "! c #629E64", 21 | "~ c #428644", 22 | "{ c #6E926C", 23 | "] c #7AEA7C", 24 | "^ c #4A964C", 25 | "/ c #62C264", 26 | "( c #52A654", 27 | "_ c #4A7E4C", 28 | ": c #82AE84", 29 | "< c #366A34", 30 | "[ c #5AB65C", 31 | "} c #4A764C", 32 | "| c #6AD26C", 33 | "1 c #8EC68C", 34 | "2 c #7A9A7C", 35 | "3 c #7AE27C", 36 | "4 c #82A684", 37 | "5 c #568E54", 38 | "6 c #568654", 39 | "7 c #3E7A3C", 40 | "8 c #6AC26C", 41 | "9 c #3E6A3C", 42 | "0 c #468244", 43 | "a c #56A254", 44 | "b c #4E8E4C", 45 | "c c #5EAE5C", 46 | "d c #86C684", 47 | "e c #427244", 48 | "f c #62A664", 49 | "g c #769A74", 50 | "h c #82F284", 51 | "i c #5A9A5C", 52 | "j c #5AA65C", 53 | "k c #428244", 54 | "l c #66BE64", 55 | "m c #6A8E6C", 56 | "n c #76DA74", 57 | "o c #7E9E7C", 58 | "p c #2A522C", 59 | "q c #5E825C", 60 | "r c #82BE84", 61 | "s c #669E64", 62 | "t c #6E966C", 63 | "u c #529A54", 64 | "v c #62C664", 65 | "w c #4A824C", 66 | "x c #366E34", 67 | "y c #72D674", 68 | "z c #427E3C", 69 | "A c #5EBE5C", 70 | "B c #52A254", 71 | "C c #628A64", 72 | "D c #4A924C", 73 | "E c #6ACE6C", 74 | "F c #5AB25C", 75 | "G c #326634", 76 | "H c #568254", 77 | "I c #7ABE7C", 78 | "J c #3A763C", 79 | "K c #468A44", 80 | "L c #7EEE7C", 81 | "M c #4E9A4C", 82 | "N c #56AA54", 83 | "O c #86B684", 84 | "P c #62B664", 85 | "Q c #162A14", 86 | "R c #529E54", 87 | "S c #72DA74", 88 | "T c #76A274", 89 | "U c #4A8E4C", 90 | "V c #264A24", 91 | "W c #5AAE5C", 92 | "X c #5EA25C", 93 | "Y c #468644", 94 | "Z c #729274", 95 | "` c #7EEA7C", 96 | " . c #4E964C", 97 | ".. c #66C264", 98 | "+. c #56A654", 99 | "@. c #4E7E4C", 100 | "#. c #8AB28C", 101 | "$. c #3A6A3C", 102 | "%. c #5EB65C", 103 | "&. c #527A54", 104 | "*. c #6ED26C", 105 | "=. c #92C694", 106 | "-. c #7E9A7C", 107 | ";. c #7AE67C", 108 | ">. c #86AA84", 109 | ",. c #5E865C", 110 | "'. c #6AC66C", 111 | "). c #3E6E3C", 112 | "!. c #5AA25C", 113 | "~. c #4E924C", 114 | "{. c #5EB25C", 115 | "]. c #467244", 116 | "^. c #86F284", 117 | "/. c #5AAA5C", 118 | "(. c #76DE74", 119 | "_. c #829E84", 120 | ":. c #325E34", 121 | "<. c #66A264", 122 | "[. c #729674", 123 | "}. c #66C664", 124 | "|. c #4E824C", 125 | "1. c #3A6E3C", 126 | "2. c #76D674", 127 | "3. c #427E44", 128 | "4. c #62BE64", 129 | "5. c #668A64", 130 | "6. c #6ECE6C", 131 | "7. c #366634", 132 | "8. c #5A825C", 133 | "9. c #7EBE7C", 134 | "0. c #3E763C", 135 | "G 7.G G G G G 7.G < z . .* k 1.G G G G G G 0.K x 7.7.7.7.7.< J Y D M D ) 7.7.7.7.7.7.< 7.7.7.7.", 136 | "7.G 7.> > > 7.G ) D M K 7 < > > > > > > > > + * < G G G G G G 7.G x k * M K x G G G G G G G G G ", 137 | "G G 7.G > > < ~ M D + G > > G > > 7.7.7.7.> 7 D x 7.7.7.7.7.G 7.7.G < ) ~ D M 7 7.7.7.7.7.7.7.7.", 138 | "7.7.G > 7.< * M ~ x > G > G > > 7.> > > > G 7 * 1.G G G G G 7.G G 7.G G G J * M ~ < G G G G G G ", 139 | "> G G > x D M k < G > G > > G > > G G G > 7.7 * x 7.7.7.7.G 7.7.G 7.7.7.7.G x ~ # Y < 7.7.7.7.7.", 140 | "G > > x ^ .0.G G G 7.> > > > > G > > > 7.> 7 U 1.G G G G 7.G G 7.G G G G 7.G < k # K < G G G G ", 141 | "G G < .^ J G G 7.G 7.> G > > > > 7.7.> 7.7.7 * x 7.7.7.G 7.7.G 7.7.7.7.G 7.G G 7.+ B ~ < 7.7.7.", 142 | "> < D M 7 G > > > G > G > > G > 7.> > G > > + U 1.G G G 7.G G 7.G G G G 7.G 7.7.G < k B + < G G ", 143 | "G k # k < 7.7.G > G > > G > > > > G x k .R F A N R U 7 x 7.G 7.7.7.7.G 7.G G 7.G G < K # J $.8.", 144 | ") ( K < > > G G 7.G G > > > G G + M +.B M D B W ^ ^ # ( +.^ ) G G G G 7.G 7.7.G 7.7.7.x u ! & o ", 145 | "^ .x > > > > G 7.7.G > > > 0. .+.M K + ) < + D ) < J k * R +.D x 7.G 7.G G 7.G G G 7.e T =.& H ", 146 | "+.+ < G G G 7.G > G G > G ~ ( B ~ ) G > G > 7 U < 7.7.G < J * B B 7 7.G 7.7.G 7.7.9 5.o Z s a ) ", 147 | "D x > > > > > G > G G < K ( D 0.> G 7.> G 7.+ * < G 7.7.G G < + # ( + G G 7.G $.,.2 [.$ ).0.( k ", 148 | "7 7.G G G G 7.G G > 7.K +.K x > G > > G > > 7 D < 7.G G 7.7.G 7.) M +.7 7.< &.[.2 C &.7.7.7.* B ", 149 | "x 7.> > > > > 7.7.G k +.* < > > > G > 7.G G 7 * < 7.7.G G 7.G G G ) M B &.[.o m &.7.G 7.G 7.) %.", 150 | "7.G 7.7.7.G 7.G G x B ^ ) > G > 7.> 7.> > > + D 7.G G 7.7.G 7.7.7.< w r #.{ , 9 7.7.7.G 7.G < ( ", 151 | "> G G > 7.G > 7.7.* ( 7 G > > > > > G 7.1.z B F D 7 < G 7.G G G $.q o : I _ < > G G 7.G 7.G 7.~ ", 152 | "7.7.> G > 7.7.> x +.* 7.> > G > G G < k # # +.[ B N ( k G 7.$.&.2 2 C |.B D < 7.7.7.G 7.G 7.G < ", 153 | "> 7.> G > G G > ~ +.+ > > > > > > < K R K + K M 3.K B W K } Z -.m &.< < Y W ) G G 7.G 7.G 7.G 7.", 154 | "> G G > > > 7.G # ^ ) > G > G > 7.~ # + < > 7 * < G J j d 4 { , $.G 7.G 7 F + 7.7.G 7.G 7.G 7.G ", 155 | "> > > G G > 7.7.N * 7.> > > > > J D Y > G 7.3.D < ).$ 4 1 ' e 7.7.G G G ) # D < G G 7.G 7.G 7.7.", 156 | "> 7.G > > G > x +.Y G > G > G > Y ~.x G > > 7 ~.8.-.2 5.i A 7 G G 7.7.7.< D # x 7.7.G 7.G 7.G G ", 157 | "< < x x < x x + ; * x x x x x ) ^ .1.) 1.) 5 r o t 6 0.K A D J ) ) ) J 7 .F k 7 7 7 7 J 0.0.x ", 158 | "D D * * D U U # A ( * * * K * * N W U U * K X 9.<.D K K R ..N U * * * * U ( A D K K K K U * K ) ", 159 | "7 z z 7 7 z 7 K {.M 7 7 7 0.0.7 # B J 7 7 7 U R 0.7 7 7 D / D 0.0.7 0.J 7 .F + 0.J 0.J 0.J 0.< ", 160 | "G > > > G > G < N K 7.> > G G > ~ D 1.G > > 3.U G G G G * A J G G G G 7.x D # x G 7.G 7.G 7.G G ", 161 | "G G G > G > G < ( * 7.> > > > > J ^ K G G > + D 7.7.7.7 N ( < 7.7.7.G G ) B * < G 7.G 7.G 7.7.G ", 162 | "G G > > > 7.G G # .) G > > G > > k u 0 7.G z U G G 7 ( F + < G G G 7.7.7 W + < 7.G 7.G 7.G G 7.", 163 | "> 7.G 7.> > > 7.~ B + > > > G G > x ~ # .+ ~ .7 D ; ; k G 7.7.7.G G G K W x G 7.G 7.G 7.7.G 7.", 164 | "7.G 7.> G 7.7.G < ( D < G > > > > > < z D # %.A +.B .7 < K = G G 7.7.J B D < 7.G 7.G 7.G G 7.x ", 165 | "G G G > > > > G G K ( 7 > > > > > G > G 1.+ R N K 7 x G ` (./.7.G G < K ; J G 7.G 7.G 7.7.G 7.Y ", 166 | "7.G G > > G G G G x B M ) > > G G > G G > > + D G G 7.7.;.E 4.G 7.7.7 N K < 7.G 7.G 7.G G 7.< ; ", 167 | "1.> G G > > > ` ] %.+ L 3 (.S S +.> /.L ;.(.S y 7.G 6.3 6.= = y ;...B # ` ] @ *.;.S B 7.G G J A ", 168 | "z G > > G 7.7.% = '.n ~.K %.= = = y *.u .4.= = {.7.c /.= = ..u M M B J y = E 6.!.b z G 7.< D W ", 169 | "M ) G > > G G y = ..7.. . +.@ '.= @ V . . 1.}.= {.. G 7.6.= B . . . . 7.y = ..> . . . . G ) [ D ", 170 | "[ + G G G > 7.S = a . . . . 4.E = z . . . G y = @ . . G (.6.a . . . . G y = .. . . . . < ^ W J ", 171 | "N B ) G G G 7.y = .. . . 7.}.6.'.0.. . . G (.= %.. . ~ y = B . . . 7.G *.'.0 . . . G 7.7 [ K < ", 172 | "+ [ D < > > G % = R . . > > }.6.}.0.. . +.+.3 = {.. . B (.E W . . G G 7.y = K . . G 7.x +.( J G ", 173 | "< D {.Y 7.> 7.y = u . . > > ..6.'.0.. . K U (.= %.. . + y = +.. . 7.G 7.y }.Y . . G < ^ F z 7.7.", 174 | "> x B ; + G > y = ( . . G > }.6.}.0.. . > G (.= {.. . G (.= {.. . G 7.G y = k . . < * [ U < G G ", 175 | "> G J +.N + G S '.R . . > G }.6.}.0.. . G G (.= [ . . G *.= }.J . G 7.G *.= ~ . . ~ %.^ x 7.7.7.", 176 | "G > G 7 +.N z y E B . . G > ..6.'.0.. . > > 3 = {.. . 7.'.= = = (.3 p 7.y '.0 . . {.# ) 7.G G G ", 177 | "G > G G 7 ( ; @ N ~.. . > > 4.W +.1.. . G 7.= /.B . . G > {.l 4.%.R G 7.@ /.+ . . M ) G 7.7.7.7.", 178 | "> 7.> > G 0.# %.^ . . . > > > > > . . > > > + D . . . 7.7.7.- - Q . . G < . . . . ) G 7.G G G G ", 179 | "G G 7.> 7.7.) ^ F . . < G > > > G . . 7.G > 3.D 7.. G G G 7.7.. . . . x D F . . < 7.G 7.7.7.7.7.", 180 | "> 7.G G > G G < ~ ( [ B + < > G > > > > > 7.+ U G 7.7.7.7.G G 7.G x K W [ R + < G G 7.G G G G G ", 181 | "> > > G > > > > 7.J D +.[ ; K x G 7.G 7.> 7.) z G G G G 7.7.< 0. .F F B ~ 1.G 7.7.G 7.7.7.7.7.7.", 182 | "G 7.7.> > G 7.G > 7.< M E | +.7 > > > > G > x ) 7.> 7.7.G G < k F % / ~ G G 7.G G 7.G G G G G G "}; 183 | -------------------------------------------------------------------------------- /mtr-curses.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* Prototypes for curses.c */ 20 | void mtr_curses_open(void); 21 | void mtr_curses_close(void); 22 | void mtr_curses_redraw(void); 23 | int mtr_curses_keyaction(void); 24 | void mtr_curses_clear(void); 25 | 26 | #define STARTSTAT 30 27 | #ifdef GRAPHCAIRO 28 | void mtr_curses_init(void); 29 | void mtr_gen_scale_gc(void); 30 | void mtr_curses_scale_desc(char *buf); 31 | char mtr_curses_saved_ch(int saved_int); 32 | int mtr_curses_data_fields(char *buf); 33 | void mtr_fill_data(int at, char *buf); 34 | #ifdef UNICODE 35 | wchar_t mtr_curses_saved_wch(int saved_int); 36 | #endif 37 | #endif 38 | -------------------------------------------------------------------------------- /mtr-gtk.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* Prototypes for gtk.c */ 20 | int gtk_detect(int *argc, char ***argv); 21 | void gtk_open(void); 22 | void gtk_close(void); 23 | void gtk_redraw(void); 24 | int gtk_keyaction(void); 25 | void gtk_loop(void); 26 | -------------------------------------------------------------------------------- /mtr.8: -------------------------------------------------------------------------------- 1 | .TH MTR 8 "March 4, 1999" "mtr" "mtr" 2 | 3 | 4 | .SH NAME 5 | mtr \- a network diagnostic tool 6 | 7 | 8 | .SH SYNOPSIS 9 | .B mtr 10 | [\c 11 | .B \-BfhvrctglxspQemniuTP46yzG\c 12 | ] 13 | [\c 14 | .B \-\-help\c 15 | ] 16 | [\c 17 | .B \-\-version\c 18 | ] 19 | [\c 20 | .B \-\-report\c 21 | ] 22 | [\c 23 | .B \-\-report-wide\c 24 | ] 25 | [\c 26 | .B \-\-report\-cycles\ COUNT\c 27 | ] 28 | [\c 29 | .B \-\-curses\c 30 | ] 31 | [\c 32 | .BI \-\-displaymode\ MODE\c 33 | ] 34 | [\c 35 | .B \-\-split\c 36 | ] 37 | [\c 38 | .B \-\-raw\c 39 | ] 40 | [ 41 | .B \-\-xml\c 42 | ] 43 | [\c 44 | .B \-\-mpls\c 45 | ] 46 | [\c 47 | .B \-\-no-dns\c 48 | ] 49 | [\c 50 | .B \-\-show-ips\c 51 | ] 52 | [\c 53 | .B \-\-gtk\c 54 | ] 55 | [\c 56 | .B \-\-address\ IP.ADD.RE.SS\c 57 | ] 58 | [\c 59 | .B \-\-interval\ SECONDS\c 60 | ] 61 | [\c 62 | .B \-\-max-ttl\ NUM\c 63 | ] 64 | [\c 65 | .B \-\-first-ttl\ NUM\c 66 | ] 67 | [\c 68 | .B \-\-bitpattern\ NUM\c 69 | ] 70 | [\c 71 | .B \-\-tos\ NUM\c 72 | ] 73 | [\c 74 | .B \-\-psize\ BYTES | -s BYTES\c 75 | ] 76 | [\c 77 | .B \-\-tcp\c 78 | ] 79 | [\c 80 | .B \-\-udp\c 81 | ] 82 | [\c 83 | .B \-\-port\ PORT\c 84 | ] 85 | [\c 86 | .B \-\-timeout\ SECONDS\c 87 | ] 88 | .B HOSTNAME [PACKETSIZE] 89 | 90 | 91 | .SH DESCRIPTION 92 | 93 | .B mtr 94 | combines the functionality of the 95 | .B traceroute 96 | and 97 | .B ping 98 | programs in a single network diagnostic tool. 99 | 100 | .PP 101 | As 102 | .B mtr 103 | starts, it investigates the network connection between the host 104 | .B mtr 105 | runs on and 106 | .BR HOSTNAME . 107 | by sending packets with purposely low TTLs. It continues to send 108 | packets with low TTL, noting the response time of the intervening 109 | routers. This allows 110 | .B mtr 111 | to print the response percentage and response times of the internet 112 | route to 113 | .BR HOSTNAME . 114 | A sudden increase in packet loss or response time is often an indication 115 | of a bad (or simply overloaded) link. 116 | 117 | .PP 118 | The results are usually reported as round-trip-response times in miliseconds 119 | and the percentage of packetloss. 120 | 121 | .SH OPTIONS 122 | 123 | .TP 124 | .B \-h 125 | .TP 126 | .B \-\-help 127 | .br 128 | Print the summary of command line argument options. 129 | 130 | .TP 131 | .B \-v 132 | .TP 133 | .B \-\-version 134 | .br 135 | Print the installed version of mtr. 136 | 137 | .TP 138 | .B \-r 139 | .TP 140 | .B \-\-report 141 | .br 142 | This option puts 143 | .B mtr 144 | into 145 | .B report 146 | mode. When in this mode, 147 | .B mtr 148 | will run for the number of cycles specified by the 149 | .B \-c 150 | option, and then print statistics and exit. 151 | .TP 152 | \c 153 | This mode is useful for generating statistics about network quality. 154 | Note that each running instance of 155 | .B mtr 156 | generates a significant amount of network traffic. Using 157 | .B mtr 158 | to measure the quality of your network may result in decreased 159 | network performance. 160 | 161 | .TP 162 | .B \-w 163 | .TP 164 | .B \-\-report-wide 165 | .br 166 | This option puts 167 | .B mtr 168 | into 169 | .B wide report 170 | mode. When in this mode, 171 | .B mtr 172 | will not cut hostnames in the report. 173 | 174 | .TP 175 | .B \-c\ COUNT 176 | .TP 177 | .B \-\-report\-cycles\ COUNT 178 | Use this option to set the number of pings sent to determine 179 | both the machines on the network and the reliability of 180 | those machines. Each cycle lasts one second. 181 | 182 | .TP 183 | .B \-s\ BYTES 184 | .TP 185 | .B \-\-psize\ BYTES 186 | .TP 187 | .B PACKETSIZE 188 | These options or a trailing PACKETSIZE on the command line sets 189 | the packet size used for probing. 190 | It is in bytes inclusive IP and ICMP headers 191 | 192 | If set to a negative number, every iteration will use a different, random 193 | packet size upto that number. 194 | .TP 195 | .B \-t 196 | .TP 197 | .B \-\-curses 198 | .br 199 | Use this option to force 200 | .B mtr 201 | to use the curses based terminal 202 | interface (if available). 203 | 204 | .TP 205 | .B \-e 206 | .TP 207 | .B \-\-mpls 208 | .br 209 | Use this option to tell 210 | .B mtr 211 | to display information from ICMP extensions for MPLS (RFC 4950) 212 | that are encoded in the response packets. 213 | 214 | .TP 215 | .B \-n 216 | .TP 217 | .B \-\-no-dns 218 | .br 219 | Use this option to force 220 | .B mtr 221 | to display numeric IP numbers and not try to resolve the 222 | host names. 223 | 224 | .TP 225 | .B \-b 226 | .TP 227 | .B \-\-show-ips 228 | .br 229 | Use this option to tell 230 | .B mtr 231 | to display both the host names and numeric IP numbers. In split mode 232 | this adds an extra field to the output. In report mode, there is usually 233 | too little space to add the IPs, and they will be truncated. Use the 234 | wide report (-w) mode to see the IPs in report mode. 235 | 236 | .TP 237 | .B \-o\ fields\ order 238 | .TP 239 | .B \-\-order\ fields\ order 240 | .br 241 | Use this option to specify the fields and their order when loading mtr. 242 | .br 243 | Available fields: 244 | .TS 245 | center allbox tab(%); 246 | ll. 247 | L%Loss ratio 248 | D%Dropped packets 249 | R%Received packets 250 | S%Sent Packets 251 | N%Newest RTT(ms) 252 | B%Min/Best RTT(ms) 253 | A%Average RTT(ms) 254 | W%Max/Worst RTT(ms) 255 | V%Standard Deviation 256 | G%Geometric Mean 257 | J%Current Jitter 258 | M%Jitter Mean/Avg. 259 | X%Worst Jitter 260 | I%Interarrival Jitter 261 | .TE 262 | .br 263 | 264 | Example: 265 | -o "LSD NBAW" 266 | .TP 267 | .B \-\-displaymode \fIMODE 268 | Use this option to select the initial display mode: 0 (default) 269 | selects statistics, 1 selects the stripchart without latency 270 | information, and 2 selects the stripchart with latency 271 | information, and 3 selects the unicode histogram, 272 | 4-7 - reserved, 4th bit - toggle color on/off 273 | .TP 274 | .B \-g 275 | .TP 276 | .B \-\-gtk 277 | .br 278 | Use this option to force 279 | .B mtr 280 | to use the GTK+ based X11 window interface (if available). 281 | GTK+ must have been available on the system when 282 | .B mtr 283 | was built for this to work. See the GTK+ web page at 284 | .B http://www.gtk.org/ 285 | for more information about GTK+. 286 | 287 | .TP 288 | .B \-z 289 | .TP 290 | .B \-\-aslookup 291 | .br 292 | Turn on ASN lookups. Origin - asn.routeviews.org (IPv4 only). 293 | 294 | Key: `z' toggle ASN info on/off 295 | 296 | .TP 297 | .B \-y\ origin,fields 298 | .TP 299 | .B \-\-ipinfo\ origin,fields 300 | .br 301 | Use this option to specify the IP info origin and their fields and order. 302 | 303 | Available origins and their fields: 304 | 1 - origin.asn.cymru.com (both IPv4 and IPv6): 305 | .br 306 | ASN, Route, CC, Registry, Allocated 307 | .br 308 | 2 - asn.routeviews.org (IPv4 only): 309 | .br 310 | ASN 311 | .br 312 | 3 - origin.asn.spameatingmonkey.net (IPv4 only): 313 | .br 314 | Route, ASN, Organization, Allocated, CC 315 | .br 316 | Default: 1,1 317 | .br 318 | Examples: 319 | .br 320 | -y3,5,2,3 (origin.asn.spameatingmonkey.net: CC ASN ORG) 321 | .br 322 | -y, (origin.asn.cymru.com: ASN) 323 | .br 324 | 325 | Key: `y' switching IP info 326 | 327 | .TP 328 | .B \-G\ arguments 329 | .TP 330 | .B \-\-graphcairo\ arguments 331 | .br 332 | Use this option to use the cairo based graph drawing (if available) 333 | and to specify their arguments. 334 | 335 | Available arguments: 336 | 1st argument: graph type 337 | .br 338 | 1 - dot, 2 - line, 3 - curve (default) 339 | .br 340 | 2nd argument: viewport period 341 | .br 342 | in N ticks, one tick - 10sec (default - 6, i.e. 60sec) 343 | .br 344 | 3rd argument: enable legend 345 | 0 - none, 1 - enable (default) 346 | .br 347 | 4th argument: enable multipath 348 | 0 - none (default), 1 - enable 349 | .br 350 | 5th argument: jitter graph instead of latency graph 351 | 0 - none (default), 1 - enable 352 | .br 353 | \",\" (comma) as argument separator 354 | .br 355 | Examples: 356 | .br 357 | -G, (default: 3,6,1,1,0 - curve, 1min, legend, multipath, latency) 358 | .br 359 | -G2 (line, default, default, default, default) 360 | .br 361 | -G,30,,0 (default, 5min, default, disable, default) 362 | .br 363 | 364 | Keys: `dejnpqrtuyz+- ' 365 | 366 | .TP 367 | .B \-p 368 | .TP 369 | .B \-\-split 370 | .br 371 | Use this option to set 372 | .B mtr 373 | to spit out a format that is suitable for a split-user interface. 374 | 375 | .TP 376 | .B \-l 377 | .TP 378 | .B \-\-raw 379 | .br 380 | Use this option to tell 381 | .B mtr 382 | to use the raw output format. This format is better suited for 383 | archival of the measurement results. It could be parsed to 384 | be presented into any of the other display methods. 385 | 386 | .TP 387 | .B \-x 388 | .TP 389 | .B \-\-xml 390 | .br 391 | Use this option to tell 392 | .B mtr 393 | to use the xml output format. This format is better suited for 394 | automated processing of the measurement results. 395 | 396 | .TP 397 | .B \-a\ IP.ADD.RE.SS 398 | .TP 399 | .B \-\-address\ IP.ADD.RE.SS 400 | .br 401 | Use this option to bind outgoing packets' socket to specific interface, 402 | so that any packet will be sent through this interface. NOTE that this 403 | option doesn't apply to DNS requests (which could be and could not be 404 | what you want). 405 | 406 | .TP 407 | .B \-i\ SECONDS 408 | .TP 409 | .B \-\-interval\ SECONDS 410 | .br 411 | Use this option to specify the positive number of seconds between ICMP 412 | ECHO requests. The default value for this parameter is one second. The 413 | root user may choose values between zero and one. 414 | 415 | .TP 416 | .B \-m\ NUM 417 | .TP 418 | .B \-\-max-ttl\ NUM 419 | .br 420 | Specifies the maximum number of hops (max time-to-live value) traceroute will 421 | probe. Default is 30. 422 | 423 | .TP 424 | .B \-f\ NUM 425 | .TP 426 | .B \-\-first-ttl\ NUM 427 | .br 428 | Specifies with what TTL to start. Defaults to 1. 429 | 430 | .TP 431 | .B \-B\ NUM 432 | .TP 433 | .B \-\-bitpattern\ NUM 434 | .br 435 | Specifies bit pattern to use in payload. Should be within range 0 - 255. 436 | 437 | .TP 438 | .B \-Q\ NUM 439 | .TP 440 | .B \-\-tos\ NUM 441 | .br 442 | Specifies value for type of service field in IP header. Should be within range 0 443 | - 255. 444 | 445 | .TP 446 | .B \-u 447 | .TP 448 | .B \-\-udp 449 | .br 450 | Use UDP datagrams instead of ICMP ECHO. 451 | 452 | .TP 453 | .B \-T 454 | .TP 455 | .B \-\-tcp 456 | .br 457 | Use TCP SYN packets instead of ICMP ECHO. PACKETSIZE is ignored, since 458 | SYN packets can not contain data. 459 | 460 | .TP 461 | .B \-P\ PORT 462 | .TP 463 | .B \-\-port\ PORT 464 | .br 465 | The target port number for TCP traces. 466 | 467 | .TP 468 | .B \-\-timeout\ SECONDS 469 | .br 470 | The number of seconds to keep the TCP socket open before giving up on 471 | the connection. This will only affect the final hop. Using large values 472 | for this, especially combined with a short interval, will use up a lot 473 | of file descriptors. 474 | 475 | .TP 476 | .B \-4 477 | .br 478 | Use IPv4 only. 479 | 480 | .TP 481 | .B \-6 482 | .br 483 | Use IPv6 only. (IPV4 may be used for DNS lookups). 484 | 485 | .SH BUGS 486 | 487 | Some modern routers give a lower priority to ICMP ECHO packets than 488 | to other network traffic. Consequently, the reliability of these 489 | routers reported by 490 | .B mtr 491 | will be significantly lower than the actual reliability of 492 | these routers. 493 | 494 | 495 | .SH CONTACT INFORMATION 496 | 497 | .PP 498 | For the latest version, see the mtr web page at 499 | .BR http://www.bitwizard.nl/mtr/ . 500 | 501 | .PP 502 | The mtr mailinglist was little used and is no longer active. 503 | 504 | .PP 505 | For patches, bug reports, or feature requests, please open an issue on 506 | GitHub at: 507 | .BR https://github.com/traviscross/mtr . 508 | 509 | .SH "SEE ALSO" 510 | 511 | traceroute(8), 512 | ping(8) 513 | TCP/IP Illustrated (Stevens, ISBN 0201633469). 514 | -------------------------------------------------------------------------------- /mtr.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #ifdef HAVE_LIBIDN 39 | #include 40 | #endif 41 | 42 | #ifdef UNICODE 43 | #ifdef HAVE_WCTYPE_H 44 | #include 45 | #endif 46 | #ifdef HAVE_LOCALE_H 47 | #include 48 | #endif 49 | #ifdef HAVE_LANGINFO_H 50 | #include 51 | #endif 52 | #endif 53 | 54 | #include "mtr.h" 55 | #include "mtr-curses.h" 56 | #include "getopt.h" 57 | #include "display.h" 58 | #include "dns.h" 59 | #include "report.h" 60 | #include "net.h" 61 | #include "asn.h" 62 | #include "version.h" 63 | #ifdef GRAPHCAIRO 64 | #include "graphcairo-mtr.h" 65 | #endif 66 | 67 | 68 | #ifdef ENABLE_IPV6 69 | #define DEFAULT_AF AF_UNSPEC 70 | #else 71 | #define DEFAULT_AF AF_INET 72 | #endif 73 | 74 | 75 | #ifdef NO_HERROR 76 | #define herror(str) fprintf(stderr, str ": error looking up \"%s\"\n", Hostname); 77 | #endif 78 | 79 | 80 | int DisplayMode; 81 | int display_mode; 82 | int display_mode_max = 3; 83 | int color_mode; 84 | int Interactive = 1; 85 | int PrintVersion = 0; 86 | int PrintHelp = 0; 87 | int MaxPing = 10; 88 | int ForceMaxPing = 0; 89 | float WaitTime = 1.0; 90 | char *Hostname = NULL; 91 | char *InterfaceAddress = NULL; 92 | char LocalHostname[128]; 93 | int dns = 1; 94 | int show_ips = 0; 95 | int enablempls = 0; 96 | int cpacketsize = 64; /* default packet size */ 97 | int bitpattern = 0; 98 | int tos = 0; 99 | int reportwide = 0; 100 | int af = DEFAULT_AF; 101 | int mtrtype = IPPROTO_ICMP; /* Use ICMP as default packet type */ 102 | pid_t mypid; 103 | 104 | /* begin ttl windows addByMin */ 105 | int fstTTL = 1; /* default start at first hop */ 106 | /*int maxTTL = MaxHost-1; */ /* max you can go is 255 hops */ 107 | int maxTTL = 30; /* inline with traceroute */ 108 | /* end ttl window stuff. */ 109 | int remoteport = 80; /* for TCP tracing */ 110 | int timeout = 10 * 1000000; /* for TCP tracing */ 111 | 112 | 113 | /* default display field(defined by key in net.h) and order */ 114 | unsigned char fld_active[2*MAXFLD] = "LS NABWV"; 115 | int fld_index[256]; 116 | char available_options[MAXFLD]; 117 | 118 | 119 | struct fields data_fields[MAXFLD] = { 120 | /* key, Remark, Header, Format, Width, CallBackFunc */ 121 | {' ', ": Space between fields", " ", " ", 1, &net_drop }, 122 | {'L', "L: Loss Ratio", "Loss%", " %4.1f%%", 6, &net_loss }, 123 | {'D', "D: Dropped Packets", "Drop", " %4d", 5, &net_drop }, 124 | {'R', "R: Received Packets", "Rcv", " %5d", 6, &net_returned}, 125 | {'S', "S: Sent Packets", "Snt", " %5d", 6, &net_xmit }, 126 | {'N', "N: Newest RTT(ms)", "Last", " %5.1f", 6, &net_last }, 127 | {'B', "B: Min/Best RTT(ms)", "Best", " %5.1f", 6, &net_best }, 128 | {'A', "A: Average RTT(ms)", "Avg", " %5.1f", 6, &net_avg }, 129 | {'W', "W: Max/Worst RTT(ms)", "Wrst", " %5.1f", 6, &net_worst }, 130 | {'V', "V: Standard Deviation", "StDev", " %5.1f", 6, &net_stdev }, 131 | {'G', "G: Geometric Mean", "Gmean", " %5.1f", 6, &net_gmean }, 132 | {'J', "J: Current Jitter", "Jttr", " %4.1f", 5, &net_jitter}, 133 | {'M', "M: Jitter Mean/Avg.", "Javg", " %4.1f", 5, &net_javg }, 134 | {'X', "X: Worst Jitter", "Jmax", " %4.1f", 5, &net_jworst}, 135 | {'I', "I: Interarrival Jitter", "Jint", " %4.1f", 5, &net_jinta }, 136 | {'\0', NULL, NULL, NULL, 0, NULL} 137 | }; 138 | 139 | typedef struct names { 140 | char* name; 141 | struct names* next; 142 | } names_t; 143 | static names_t *names = NULL; 144 | 145 | char * 146 | trim(char * s) { 147 | 148 | char * p = s; 149 | int l = strlen(p); 150 | 151 | while(isspace((int)p[l-1]) && l) p[--l] = 0; 152 | while(*p && isspace((int)*p) && l) ++p, --l; 153 | 154 | return p; 155 | } 156 | 157 | static void 158 | append_to_names(const char* progname, const char* item) { 159 | 160 | names_t* name = calloc(1, sizeof(names_t)); 161 | if (name == NULL) { 162 | fprintf(stderr, "%s: memory allocation failure\n", progname); 163 | exit(EXIT_FAILURE); 164 | } 165 | // prepared for adding NULL name, but decided against that in the end. 166 | name->name = strdup(item); 167 | name->next = names; 168 | names = name; 169 | } 170 | 171 | static void 172 | read_from_file(const char* progname, const char *filename) { 173 | 174 | FILE *in; 175 | char line[512]; 176 | 177 | if (! filename || strcmp(filename, "-") == 0) { 178 | clearerr(stdin); 179 | in = stdin; 180 | } else { 181 | in = fopen(filename, "r"); 182 | if (! in) { 183 | fprintf(stderr, "%s: fopen: %s\n", progname, strerror(errno)); 184 | exit(EXIT_FAILURE); 185 | } 186 | } 187 | 188 | while (fgets(line, sizeof(line), in)) { 189 | char* name = trim(line); 190 | append_to_names(progname, name); 191 | } 192 | 193 | if (ferror(in)) { 194 | fprintf(stderr, "%s: ferror: %s\n", progname, strerror(errno)); 195 | exit(EXIT_FAILURE); 196 | } 197 | 198 | if (in != stdin) fclose(in); 199 | } 200 | 201 | /* 202 | * If the file stream is associated with a regular file, lock the file 203 | * in order coordinate writes to a common file from multiple mtr 204 | * instances. This is useful if, for example, multiple mtr instances 205 | * try to append results to a common file. 206 | */ 207 | 208 | static void 209 | lock(const char* progname, FILE *f) { 210 | int fd; 211 | struct stat buf; 212 | static struct flock lock; 213 | 214 | assert(f); 215 | 216 | lock.l_type = F_WRLCK; 217 | lock.l_start = 0; 218 | lock.l_whence = SEEK_END; 219 | lock.l_len = 0; 220 | lock.l_pid = mypid; 221 | 222 | fd = fileno(f); 223 | if ((fstat(fd, &buf) == 0) && S_ISREG(buf.st_mode)) { 224 | if (fcntl(fd, F_SETLKW, &lock) == -1) { 225 | fprintf(stderr, "%s: fcntl: %s (ignored)\n", 226 | progname, strerror(errno)); 227 | } 228 | } 229 | } 230 | 231 | /* 232 | * If the file stream is associated with a regular file, unlock the 233 | * file (which presumably has previously been locked). 234 | */ 235 | 236 | static void 237 | unlock(const char* progname, FILE *f) { 238 | int fd; 239 | struct stat buf; 240 | static struct flock lock; 241 | 242 | assert(f); 243 | 244 | lock.l_type = F_UNLCK; 245 | lock.l_start = 0; 246 | lock.l_whence = SEEK_END; 247 | lock.l_len = 0; 248 | lock.l_pid = mypid; 249 | 250 | fd = fileno(f); 251 | if ((fstat(fd, &buf) == 0) && S_ISREG(buf.st_mode)) { 252 | if (fcntl(fd, F_SETLKW, &lock) == -1) { 253 | fprintf(stderr, "%s: fcntl: %s (ignored)\n", 254 | progname, strerror(errno)); 255 | } 256 | } 257 | } 258 | 259 | 260 | void init_fld_options (void) 261 | { 262 | int i; 263 | 264 | for (i=0;i < 256;i++) 265 | fld_index[i] = -1; 266 | 267 | for (i=0;data_fields[i].key != 0;i++) { 268 | available_options[i] = data_fields[i].key; 269 | fld_index[data_fields[i].key] = i; 270 | } 271 | available_options[i] = 0; 272 | } 273 | 274 | int my_getopt_long(int argc, char *argv[], struct option *long_options) { 275 | static char *short_options; 276 | char *p; 277 | int i; 278 | 279 | if (!short_options) { 280 | short_options = malloc (128); 281 | if (!short_options) return -1; // Trouble! 282 | 283 | p = short_options; 284 | for (i = 0; long_options[i].name; i++) { 285 | *p++ = (char)long_options[i].val; 286 | if (long_options[i].has_arg) 287 | *p++ = ':'; 288 | } 289 | *p++ = '\0'; 290 | } 291 | return getopt_long (argc, argv, short_options, long_options, NULL); 292 | } 293 | 294 | 295 | void parse_arg (int argc, char **argv) 296 | { 297 | int opt; 298 | int i; 299 | static struct option long_options[] = { 300 | { "version", 0, 0, 'v' }, 301 | { "help", 0, 0, 'h' }, 302 | 303 | { "report", 0, 0, 'r' }, 304 | { "report-wide", 0, 0, 'w' }, 305 | { "xml", 0, 0, 'x' }, 306 | { "curses", 0, 0, 't' }, 307 | { "gtk", 0, 0, 'g' }, 308 | { "raw", 0, 0, 'l' }, 309 | { "csv", 0, 0, 'C' }, 310 | { "displaymode", 1, 0, 'd' }, 311 | { "split", 0, 0, 'p' }, /* BL */ 312 | /* maybe above should change to -d 'x' */ 313 | 314 | { "order", 1, 0, 'o' }, /* fileds to display & their order */ 315 | 316 | { "interval", 1, 0, 'i' }, 317 | { "report-cycles", 1, 0, 'c' }, 318 | { "psize", 1, 0, 's' }, /* changed 'p' to 's' to match ping option 319 | overload psize<0, ->rand(min,max) */ 320 | { "bitpattern", 1, 0, 'B' },/* overload b>255, ->rand(0,255) */ 321 | { "tos", 1, 0, 'Q' }, /* typeof service (0,255) */ 322 | { "mpls", 0, 0, 'e' }, 323 | { "no-dns", 0, 0, 'n' }, 324 | { "show-ips", 0, 0, 'b' }, 325 | { "address", 1, 0, 'a' }, 326 | { "first-ttl", 1, 0, 'f' }, /* -f & -m are borrowed from traceroute */ 327 | { "filename", 1, 0, 'F' }, 328 | { "max-ttl", 1, 0, 'm' }, 329 | { "udp", 0, 0, 'u' }, /* UDP (default is ICMP) */ 330 | { "tcp", 0, 0, 'T' }, /* TCP (default is ICMP) */ 331 | { "port", 1, 0, 'P' }, /* target port number for TCP */ 332 | { "timeout", 1, 0, 'Z' }, /* timeout for TCP sockets */ 333 | { "inet", 0, 0, '4' }, /* IPv4 only */ 334 | { "inet6", 0, 0, '6' }, /* IPv6 only */ 335 | #ifdef IPINFO 336 | { "ipinfo", 1, 0, 'y' }, 337 | { "aslookup", 0, 0, 'z' }, 338 | #endif 339 | #ifdef GRAPHCAIRO 340 | { "graphcairo", 1, 0, 'G' }, 341 | #endif 342 | { 0, 0, 0, 0 } 343 | }; 344 | 345 | opt = 0; 346 | while(1) { 347 | /* added f:m:o: byMin */ 348 | opt = my_getopt_long(argc, argv, long_options); 349 | if(opt == -1) 350 | break; 351 | 352 | switch(opt) { 353 | case 'v': 354 | PrintVersion = 1; 355 | break; 356 | case 'h': 357 | PrintHelp = 1; 358 | break; 359 | 360 | case 'r': 361 | DisplayMode = DisplayReport; 362 | break; 363 | case 'w': 364 | reportwide = 1; 365 | DisplayMode = DisplayReport; 366 | break; 367 | case 't': 368 | DisplayMode = DisplayCurses; 369 | break; 370 | case 'g': 371 | DisplayMode = DisplayGTK; 372 | break; 373 | case 'p': /* BL */ 374 | DisplayMode = DisplaySplit; 375 | break; 376 | case 'l': 377 | DisplayMode = DisplayRaw; 378 | break; 379 | case 'C': 380 | DisplayMode = DisplayCSV; 381 | break; 382 | case 'x': 383 | DisplayMode = DisplayXML; 384 | break; 385 | case 'd': 386 | display_mode = ((atoi(optarg)) & ~8) % display_mode_max; 387 | color_mode = ((atoi(optarg)) & 8) ? 1 : 0; 388 | break; 389 | case 'c': 390 | MaxPing = atoi (optarg); 391 | ForceMaxPing = 1; 392 | break; 393 | case 's': 394 | cpacketsize = atoi (optarg); 395 | break; 396 | case 'a': 397 | InterfaceAddress = optarg; 398 | break; 399 | case 'e': 400 | enablempls = 1; 401 | break; 402 | case 'n': 403 | dns = 0; 404 | break; 405 | case 'i': 406 | WaitTime = atof (optarg); 407 | if (WaitTime <= 0.0) { 408 | fprintf (stderr, "mtr: wait time must be positive\n"); 409 | exit (1); 410 | } 411 | if (getuid() != 0 && WaitTime < 1.0) { 412 | fprintf (stderr, "non-root users cannot request an interval < 1.0 seconds\r\n"); 413 | exit (1); 414 | } 415 | break; 416 | case 'f': 417 | fstTTL = atoi (optarg); 418 | if (fstTTL > maxTTL) { 419 | fstTTL = maxTTL; 420 | } 421 | if (fstTTL < 1) { /* prevent 0 hop */ 422 | fstTTL = 1; 423 | } 424 | break; 425 | case 'F': 426 | read_from_file(argv[0], optarg); 427 | break; 428 | case 'm': 429 | maxTTL = atoi (optarg); 430 | if (maxTTL > (MaxHost - 1)) { 431 | maxTTL = MaxHost-1; 432 | } 433 | if (maxTTL < 1) { /* prevent 0 hop */ 434 | maxTTL = 1; 435 | } 436 | if (fstTTL > maxTTL) { /* don't know the pos of -m or -f */ 437 | fstTTL = maxTTL; 438 | } 439 | break; 440 | case 'o': 441 | /* Check option before passing it on to fld_active. */ 442 | if (strlen (optarg) > MAXFLD) { 443 | fprintf (stderr, "Too many fields: %s\n", optarg); 444 | exit (1); 445 | } 446 | for (i=0; optarg[i]; i++) { 447 | if(!strchr (available_options, optarg[i])) { 448 | fprintf (stderr, "Unknown field identifier: %c\n", optarg[i]); 449 | exit (1); 450 | } 451 | } 452 | strcpy ((char*)fld_active, optarg); 453 | break; 454 | case 'B': 455 | bitpattern = atoi (optarg); 456 | if (bitpattern > 255) 457 | bitpattern = -1; 458 | break; 459 | case 'Q': 460 | tos = atoi (optarg); 461 | if (tos > 255 || tos < 0) { 462 | /* error message, should do more checking for valid values, 463 | * details in rfc2474 */ 464 | tos = 0; 465 | } 466 | break; 467 | case 'u': 468 | if (mtrtype != IPPROTO_ICMP) { 469 | fprintf(stderr, "-u and -T are mutually exclusive.\n"); 470 | exit(EXIT_FAILURE); 471 | } 472 | mtrtype = IPPROTO_UDP; 473 | break; 474 | case 'T': 475 | if (mtrtype != IPPROTO_ICMP) { 476 | fprintf(stderr, "-u and -T are mutually exclusive.\n"); 477 | exit(EXIT_FAILURE); 478 | } 479 | mtrtype = IPPROTO_TCP; 480 | break; 481 | case 'b': 482 | show_ips = 1; 483 | break; 484 | case 'P': 485 | remoteport = atoi(optarg); 486 | if (remoteport > 65535 || remoteport < 1) { 487 | fprintf(stderr, "Illegal port number.\n"); 488 | exit(EXIT_FAILURE); 489 | } 490 | break; 491 | case 'Z': 492 | timeout = atoi(optarg); 493 | timeout *= 1000000; 494 | break; 495 | case '4': 496 | af = AF_INET; 497 | break; 498 | case '6': 499 | #ifdef ENABLE_IPV6 500 | af = AF_INET6; 501 | break; 502 | #else 503 | fprintf( stderr, "IPv6 not enabled.\n" ); 504 | break; 505 | #endif 506 | #ifdef IPINFO 507 | case 'y': 508 | ii_parsearg(optarg); 509 | break; 510 | case 'z': 511 | ii_parsearg(NULL); 512 | break; 513 | #endif 514 | #ifdef GRAPHCAIRO 515 | case 'G': 516 | gc_parsearg(optarg); 517 | DisplayMode = DisplayGraphCairo; 518 | break; 519 | #endif 520 | } 521 | } 522 | 523 | if (DisplayMode == DisplayReport || 524 | DisplayMode == DisplayTXT || 525 | DisplayMode == DisplayXML || 526 | DisplayMode == DisplayRaw || 527 | DisplayMode == DisplayCSV) 528 | Interactive = 0; 529 | 530 | if (optind > argc - 1) 531 | return; 532 | 533 | } 534 | 535 | 536 | void parse_mtr_options (char *string) 537 | { 538 | int argc; 539 | char *argv[128], *p; 540 | 541 | if (!string) return; 542 | 543 | argv[0] = "mtr"; 544 | argc = 1; 545 | p = strtok (string, " \t"); 546 | while (p != NULL && ((size_t) argc < (sizeof(argv)/sizeof(argv[0])))) { 547 | argv[argc++] = p; 548 | p = strtok (NULL, " \t"); 549 | } 550 | if (p != NULL) { 551 | fprintf (stderr, "Warning: extra arguments ignored: %s", p); 552 | } 553 | 554 | parse_arg (argc, argv); 555 | optind = 0; 556 | } 557 | 558 | 559 | int main(int argc, char **argv) 560 | { 561 | struct hostent * host = NULL; 562 | int net_preopen_result; 563 | #ifdef ENABLE_IPV6 564 | struct addrinfo hints, *res; 565 | int error; 566 | struct hostent trhost; 567 | char * alptr[2]; 568 | struct sockaddr_in * sa4; 569 | struct sockaddr_in6 * sa6; 570 | #endif 571 | 572 | /* Get the raw sockets first thing, so we can drop to user euid immediately */ 573 | 574 | if ( ( net_preopen_result = net_preopen () ) ) { 575 | fprintf( stderr, "mtr: unable to get raw sockets.\n" ); 576 | exit( EXIT_FAILURE ); 577 | } 578 | 579 | /* Now drop to user permissions */ 580 | if (setgid(getgid()) || setuid(getuid())) { 581 | fprintf (stderr, "mtr: Unable to drop permissions.\n"); 582 | exit(1); 583 | } 584 | 585 | /* Double check, just in case */ 586 | if ((geteuid() != getuid()) || (getegid() != getgid())) { 587 | fprintf (stderr, "mtr: Unable to drop permissions.\n"); 588 | exit(1); 589 | } 590 | 591 | mypid = getpid(); 592 | 593 | /* reset the random seed */ 594 | srand(mypid); 595 | 596 | display_detect(&argc, &argv); 597 | display_mode = 0; 598 | 599 | /* The field options are now in a static array all together, 600 | but that requires a run-time initialization. */ 601 | init_fld_options (); 602 | 603 | #ifdef UNICODE 604 | int dm_histogram = 0; 605 | char *lc_ctype = setlocale(LC_CTYPE, NULL); 606 | setlocale(LC_CTYPE, ""); 607 | if (strcasecmp("UTF-8", nl_langinfo(CODESET)) == 0) { 608 | if (iswprint(L'▁')) 609 | dm_histogram = 1; 610 | else 611 | fprintf(stderr, "Oops: Unicode block elements are not printable\n"); 612 | } 613 | if (dm_histogram) 614 | display_mode_max++; 615 | else 616 | setlocale(LC_CTYPE, lc_ctype); 617 | #endif 618 | parse_mtr_options (getenv ("MTR_OPTIONS")); 619 | 620 | parse_arg (argc, argv); 621 | 622 | while (optind < argc) { 623 | char* name = argv[optind++]; 624 | append_to_names(argv[0], name); 625 | } 626 | 627 | /* Now that we know mtrtype we can select which socket to use */ 628 | if (net_selectsocket() != 0) { 629 | fprintf( stderr, "mtr: Couldn't determine raw socket type.\n" ); 630 | exit( EXIT_FAILURE ); 631 | } 632 | 633 | if (PrintVersion) { 634 | printf ("mtr " MTR_VERSION "\n"); 635 | exit(0); 636 | } 637 | 638 | if (PrintHelp) { 639 | printf("usage: %s [-BfhvrwctglxspQomniuT46] [--help] [--version]\n" 640 | "\t\t[--report] [--report-wide] [--report-cycles=COUNT]\n" 641 | "\t\t[--curses] [--displaymode|-d MODE] [--gtk]\n" 642 | "\t\t[--csv|-C] [--raw] [--xml] [--split] [--mpls] [--no-dns] [--show-ips]\n" 643 | "\t\t[--address interface] [--filename=FILE|-F]\n" /* BL */ 644 | #ifdef IPINFO 645 | "\t\t[--aslookup|-z] [--ipinfo|-y origin,fields]\n" 646 | #endif 647 | #ifdef GRAPHCAIRO 648 | "\t\t[--graphcairo|-G graphtype,timeperiod,enable_legend,enable_multipath,jitter_graph]\n" 649 | #endif 650 | "\t\t[--psize=bytes/-s bytes] [--order fields]\n" /* ok */ 651 | "\t\t[--report-wide|-w] [--inet] [--inet6] [--max-ttl=NUM] [--first-ttl=NUM]\n" 652 | "\t\t[--bitpattern=NUM] [--tos=NUM] [--udp] [--tcp] [--port=PORT] [--timeout=SECONDS]\n" /* rew */ 653 | "\t\t[--interval=SECONDS] HOSTNAME\n", argv[0]); 654 | exit(0); 655 | } 656 | 657 | time_t now = time(NULL); 658 | 659 | if (!names) append_to_names (argv[0], "localhost"); // default: localhost. 660 | 661 | names_t* head = names; 662 | while (names != NULL) { 663 | 664 | Hostname = names->name; 665 | // if (Hostname == NULL) Hostname = "localhost"; // no longer necessary. 666 | if (gethostname(LocalHostname, sizeof(LocalHostname))) { 667 | strcpy(LocalHostname, "UNKNOWNHOST"); 668 | } 669 | 670 | if (net_preopen_result != 0) { 671 | fprintf(stderr, "mtr: Unable to get raw socket. (Executable not suid?)\n"); 672 | if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE); 673 | else { 674 | names = names->next; 675 | continue; 676 | } 677 | } 678 | 679 | #ifdef ENABLE_IPV6 680 | /* gethostbyname2() is deprecated so we'll use getaddrinfo() instead. */ 681 | bzero( &hints, sizeof hints ); 682 | hints.ai_family = af; 683 | hints.ai_socktype = SOCK_DGRAM; 684 | error = getaddrinfo( Hostname, NULL, &hints, &res ); 685 | #ifdef HAVE_LIBIDN 686 | if (error) { 687 | char *z_hostname; 688 | if (idna_to_ascii_lz(Hostname, &z_hostname, 0) == IDNA_SUCCESS) 689 | error = getaddrinfo(z_hostname, NULL, &hints, &res); 690 | if (error) 691 | if (idna_to_ascii_8z(Hostname, &z_hostname, 0) == IDNA_SUCCESS) 692 | error = getaddrinfo(z_hostname, NULL, &hints, &res); 693 | } 694 | #endif 695 | if ( error ) { 696 | if (error == EAI_SYSTEM) 697 | perror ("Failed to resolve host"); 698 | else 699 | fprintf (stderr, "Failed to resolve host: %s\n", gai_strerror(error)); 700 | 701 | if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE); 702 | else { 703 | names = names->next; 704 | continue; 705 | } 706 | } 707 | /* Convert the first addrinfo into a hostent. */ 708 | host = &trhost; 709 | bzero( host, sizeof trhost ); 710 | host->h_name = res->ai_canonname; 711 | host->h_aliases = NULL; 712 | host->h_addrtype = res->ai_family; 713 | af = res->ai_family; 714 | host->h_length = res->ai_addrlen; 715 | host->h_addr_list = alptr; 716 | switch ( af ) { 717 | case AF_INET: 718 | sa4 = (struct sockaddr_in *) res->ai_addr; 719 | alptr[0] = (void *) &(sa4->sin_addr); 720 | break; 721 | case AF_INET6: 722 | sa6 = (struct sockaddr_in6 *) res->ai_addr; 723 | alptr[0] = (void *) &(sa6->sin6_addr); 724 | break; 725 | default: 726 | fprintf( stderr, "mtr unknown address type\n" ); 727 | if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE); 728 | else { 729 | names = names->next; 730 | continue; 731 | } 732 | } 733 | alptr[1] = NULL; 734 | #else 735 | host = gethostbyname(Hostname); 736 | #ifdef HAVE_LIBIDN 737 | if (host == NULL) { 738 | char *z_hostname; 739 | if (idna_to_ascii_lz(Hostname, &z_hostname, 0) == IDNA_SUCCESS) 740 | host = gethostbyname(z_hostname); 741 | if (host == NULL) 742 | if (idna_to_ascii_8z(Hostname, &z_hostname, 0) == IDNA_SUCCESS) 743 | host = gethostbyname(z_hostname); 744 | } 745 | #endif 746 | if (host == NULL) { 747 | herror("mtr gethostbyname"); 748 | if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE); 749 | else { 750 | names = names->next; 751 | continue; 752 | } 753 | } 754 | af = host->h_addrtype; 755 | #endif 756 | 757 | if (net_open(host) != 0) { 758 | fprintf(stderr, "mtr: Unable to start net module.\n"); 759 | if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE); 760 | else { 761 | names = names->next; 762 | continue; 763 | } 764 | } 765 | 766 | if (net_set_interfaceaddress (InterfaceAddress) != 0) { 767 | fprintf( stderr, "mtr: Couldn't set interface address.\n" ); 768 | if ( DisplayMode != DisplayCSV ) exit(EXIT_FAILURE); 769 | else { 770 | names = names->next; 771 | continue; 772 | } 773 | } 774 | 775 | lock(argv[0], stdout); 776 | display_open(); 777 | dns_open(); 778 | display_loop(); 779 | net_end_transit(); 780 | display_close(now); 781 | unlock(argv[0], stdout); 782 | 783 | if ( DisplayMode != DisplayCSV ) break; 784 | else names = names->next; 785 | 786 | } 787 | 788 | net_close(); 789 | 790 | while (head != NULL) { 791 | names_t* item = head; 792 | free(item->name); item->name = NULL; 793 | head = head->next; 794 | free(item); item = NULL; 795 | } 796 | head=NULL; 797 | 798 | return 0; 799 | } 800 | -------------------------------------------------------------------------------- /mtr.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | Copyright (C) 2005 R.E.Wolff@BitWizard.nl 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 2 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 | */ 19 | 20 | /* Typedefs */ 21 | 22 | /* Find the proper type for 8 bits */ 23 | #if SIZEOF_UNSIGNED_CHAR == 1 24 | typedef unsigned char uint8; 25 | #else 26 | #error No 8 bit type 27 | #endif 28 | 29 | /* Find the proper type for 16 bits */ 30 | #if SIZEOF_UNSIGNED_SHORT == 2 31 | typedef unsigned short uint16; 32 | #elif SIZEOF_UNSIGNED_INT == 2 33 | typedef unsigned int uint16; 34 | #elif SIZEOF_UNSIGNED_LONG == 2 35 | typedef unsigned long uint16; 36 | #else 37 | #error No 16 bit type 38 | #endif 39 | 40 | /* Find the proper type for 32 bits */ 41 | #if SIZEOF_UNSIGNED_SHORT == 4 42 | typedef unsigned short uint32; 43 | #elif SIZEOF_UNSIGNED_INT == 4 44 | typedef unsigned int uint32; 45 | #elif SIZEOF_UNSIGNED_LONG == 4 46 | typedef unsigned long uint32; 47 | #else 48 | #error No 32 bit type 49 | #endif 50 | 51 | typedef unsigned char byte; 52 | typedef unsigned short word; 53 | typedef unsigned long dword; 54 | 55 | #ifdef ENABLE_IPV6 56 | typedef struct in6_addr ip_t; 57 | #else 58 | typedef struct in_addr ip_t; 59 | #endif 60 | 61 | extern int enablempls; 62 | extern int dns; 63 | extern int show_ips; 64 | extern int use_dns; 65 | 66 | #ifdef __GNUC__ 67 | #define UNUSED __attribute__((__unused__)) 68 | #else 69 | #define UNUSED 70 | #endif 71 | 72 | #ifndef HAVE_SOCKLEN_T 73 | typedef int socklen_t; 74 | #endif 75 | 76 | char * 77 | trim(char * s); 78 | -------------------------------------------------------------------------------- /net.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | /* Prototypes for functions in net.c */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #ifdef ENABLE_IPV6 25 | #include 26 | #include 27 | #endif 28 | 29 | int net_preopen(void); 30 | int net_selectsocket(void); 31 | int net_open(struct hostent *host); 32 | void net_reopen(struct hostent *address); 33 | int net_set_interfaceaddress (char *InterfaceAddress); 34 | void net_reset(void); 35 | void net_close(void); 36 | int net_waitfd(void); 37 | void net_process_return(void); 38 | 39 | int net_max(void); 40 | int net_min(void); 41 | int net_last(int at); 42 | ip_t * net_addr(int at); 43 | void * net_mpls(int at); 44 | void * net_mplss(int, int); 45 | int net_loss(int at); 46 | int net_drop(int at); 47 | int net_last(int at); 48 | int net_best(int at); 49 | int net_worst(int at); 50 | int net_avg(int at); 51 | int net_gmean(int at); 52 | int net_stdev(int at); 53 | int net_jitter(int at); 54 | int net_jworst(int at); 55 | int net_javg(int at); 56 | int net_jinta(int at); 57 | ip_t * net_addrs(int at, int i); 58 | char *net_localaddr(void); 59 | 60 | int net_send_batch(void); 61 | void net_end_transit(void); 62 | 63 | int calc_deltatime (float WaitTime); 64 | 65 | int net_returned(int at); 66 | int net_xmit(int at); 67 | int net_transit(int at); 68 | 69 | int net_up(int at); 70 | 71 | #define SAVED_PINGS 200 72 | int* net_saved_pings(int at); 73 | void net_save_xmit(int at); 74 | void net_save_return(int at, int seq, int ms); 75 | int net_duplicate(int at, int seq); 76 | 77 | void sockaddrtop( struct sockaddr * saddr, char * strptr, size_t len ); 78 | int addrcmp( char * a, char * b, int af ); 79 | void addrcpy( char * a, char * b, int af ); 80 | 81 | int net_process_tcp_fds(void); 82 | 83 | #define MAXPATH 8 84 | #define MaxHost 256 85 | #define MinSequence 33000 86 | #define MaxSequence 65536 87 | 88 | #define MAXPACKET 4470 /* largest test packet size */ 89 | #define MINPACKET 28 /* 20 bytes IP header and 8 bytes ICMP or UDP */ 90 | #define MAXLABELS 8 /* http://kb.juniper.net/KB2190 (+ 3 just in case) */ 91 | 92 | /* stuff used by display such as report, curses... */ 93 | #define MAXFLD 20 /* max stats fields to display */ 94 | 95 | #if defined (__STDC__) && __STDC__ 96 | #define CONST const 97 | #else 98 | #define CONST /* */ 99 | #endif 100 | 101 | 102 | /* XXX This doesn't really belong in this header file, but as the 103 | right c-files include it, it will have to do for now. */ 104 | 105 | /* dynamic field drawing */ 106 | struct fields { 107 | CONST unsigned char key; 108 | CONST char *descr; 109 | CONST char *title; 110 | CONST char *format; 111 | int length; 112 | int (*net_xxx)(); 113 | }; 114 | 115 | extern struct fields data_fields[MAXFLD]; 116 | 117 | 118 | /* keys: the value in the array is the index number in data_fields[] */ 119 | extern int fld_index[]; 120 | extern unsigned char fld_active[]; 121 | extern char available_options[]; 122 | 123 | ip_t unspec_addr; 124 | 125 | /* MPLS label object */ 126 | struct mplslen { 127 | unsigned long label[MAXLABELS]; /* label value */ 128 | uint8 exp[MAXLABELS]; /* experimental bits */ 129 | uint8 ttl[MAXLABELS]; /* MPLS TTL */ 130 | char s[MAXLABELS]; /* bottom of stack */ 131 | char labels; /* how many labels did we get? */ 132 | }; 133 | 134 | void decodempls(int, char *, struct mplslen *, int); 135 | -------------------------------------------------------------------------------- /raw.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1998 R.E.Wolff@BitWizard.nl 4 | 5 | raw.c -- raw output (for logging for later analysis) 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License version 2 as 9 | published by the Free Software Foundation. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | #include "config.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "mtr.h" 32 | #include "raw.h" 33 | #include "net.h" 34 | #include "dns.h" 35 | 36 | static int havename[MaxHost]; 37 | 38 | extern int af; 39 | 40 | #if 0 41 | static char *addr_to_str(ip_t addr) 42 | { 43 | static char buf[20]; 44 | 45 | sprintf (buf, "%s", strlongip( &addr )); 46 | return buf; 47 | } 48 | #endif 49 | 50 | void raw_rawping (int host, int msec) 51 | { 52 | char *name; 53 | 54 | if (dns && !havename[host]) { 55 | name = dns_lookup2(net_addr(host)); 56 | if (name) { 57 | havename[host]++; 58 | printf ("d %d %s\n", host, name); 59 | } 60 | } 61 | printf ("p %d %d\n", host, msec); 62 | fflush (stdout); 63 | } 64 | 65 | 66 | void raw_rawhost (int host, ip_t * ip_addr) 67 | { 68 | printf ("h %d %s\n", host, strlongip( ip_addr )); 69 | fflush (stdout); 70 | } 71 | -------------------------------------------------------------------------------- /raw.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1998 R.E.Wolff@BitWizard.nl 4 | 5 | raw.h -- raw output (for logging for later analysis) 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License version 2 as 9 | published by the Free Software Foundation. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | /* Prototypes for raw.c */ 22 | void raw_rawping(int host, int msec); 23 | void raw_rawhost(int host, ip_t * addr); 24 | -------------------------------------------------------------------------------- /report.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "mtr.h" 31 | #include "version.h" 32 | #include "report.h" 33 | #include "net.h" 34 | #include "dns.h" 35 | #include "asn.h" 36 | 37 | #define MAXLOADBAL 5 38 | 39 | extern int dns; 40 | extern char LocalHostname[]; 41 | extern char *Hostname; 42 | extern int fstTTL; 43 | extern int maxTTL; 44 | extern int cpacketsize; 45 | extern int bitpattern; 46 | extern int tos; 47 | extern int MaxPing; 48 | extern int af; 49 | extern int reportwide; 50 | 51 | 52 | char *get_time_string (void) 53 | { 54 | time_t now; 55 | char *t; 56 | now = time (NULL); 57 | t = ctime (&now); 58 | t [ strlen (t) -1] = 0; // remove the trailing newline 59 | return t; 60 | } 61 | 62 | void report_open(void) 63 | { 64 | printf ("Start: %s\n", get_time_string ()); 65 | } 66 | 67 | static size_t snprint_addr(char *dst, size_t dst_len, ip_t *addr) 68 | { 69 | if(addrcmp((void *) addr, (void *) &unspec_addr, af)) { 70 | struct hostent *host = dns ? addr2host((void *) addr, af) : NULL; 71 | if (!host) return snprintf(dst, dst_len, "%s", strlongip(addr)); 72 | else if (dns && show_ips) 73 | return snprintf(dst, dst_len, "%s (%s)", host->h_name, strlongip(addr)); 74 | else return snprintf(dst, dst_len, "%s", host->h_name); 75 | } else return snprintf(dst, dst_len, "%s", "???"); 76 | } 77 | 78 | 79 | #ifdef IPINFO 80 | void print_mpls(struct mplslen *mpls) { 81 | int k; 82 | for (k=0; k < mpls->labels; k++) 83 | printf(" [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]); 84 | } 85 | #endif 86 | 87 | void report_close(void) 88 | { 89 | int i, j, at, max, z, w; 90 | struct mplslen *mpls, *mplss; 91 | ip_t *addr; 92 | ip_t *addr2 = NULL; 93 | char name[81]; 94 | char buf[1024]; 95 | char fmt[16]; 96 | int len=0; 97 | int len_hosts = 33; 98 | 99 | if (reportwide) 100 | { 101 | // get the longest hostname 102 | len_hosts = strlen(LocalHostname); 103 | max = net_max(); 104 | at = net_min(); 105 | for (; at < max; at++) { 106 | int nlen; 107 | addr = net_addr(at); 108 | if ((nlen = snprint_addr(name, sizeof(name), addr))) 109 | if (len_hosts < nlen) 110 | len_hosts = nlen; 111 | } 112 | } 113 | 114 | #ifdef IPINFO 115 | int len_tmp = len_hosts; 116 | if (enable_ipinfo && reportwide) 117 | len_tmp += ii_getwidth() - 1; 118 | snprintf( fmt, sizeof(fmt), "HOST: %%-%ds", len_tmp); 119 | #else 120 | snprintf( fmt, sizeof(fmt), "HOST: %%-%ds", len_hosts); 121 | #endif 122 | snprintf(buf, sizeof(buf), fmt, LocalHostname); 123 | len = reportwide ? strlen(buf) : len_hosts; 124 | for( i=0; ilabels && z == 1 && enablempls) 190 | print_mpls(mpls); 191 | snprint_addr(name, sizeof(name), addr2); 192 | printf(" %s%s\n", fmt_ipinfo(addr2), name); 193 | if (enablempls) 194 | print_mpls(mplss); 195 | } else { 196 | #else 197 | int k; 198 | if (mpls->labels && z == 1 && enablempls) { 199 | for (k=0; k < mpls->labels; k++) { 200 | printf(" | |+-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]); 201 | } 202 | } 203 | 204 | if (z == 1) { 205 | printf (" | `|-- %s\n", strlongip(addr2)); 206 | for (k=0; k < mplss->labels && enablempls; k++) { 207 | printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mplss->label[k], mplss->exp[k], mplss->s[k], mplss->ttl[k]); 208 | } 209 | } else { 210 | printf (" | |-- %s\n", strlongip(addr2)); 211 | for (k=0; k < mplss->labels && enablempls; k++) { 212 | printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mplss->label[k], mplss->exp[k], mplss->s[k], mplss->ttl[k]); 213 | } 214 | } 215 | #endif 216 | #ifdef IPINFO 217 | } 218 | #endif 219 | } 220 | } 221 | 222 | /* No multipath */ 223 | #ifdef IPINFO 224 | if (enable_ipinfo) { 225 | if (mpls->labels && z == 1 && enablempls) 226 | print_mpls(mpls); 227 | } else { 228 | #endif 229 | if(mpls->labels && z == 1 && enablempls) { 230 | int k; 231 | for (k=0; k < mpls->labels; k++) { 232 | printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]); 233 | } 234 | } 235 | #ifdef IPINFO 236 | } 237 | #endif 238 | } 239 | } 240 | 241 | 242 | void txt_open(void) 243 | { 244 | } 245 | 246 | 247 | void txt_close(void) 248 | { 249 | report_close(); 250 | } 251 | 252 | 253 | 254 | void xml_open(void) 255 | { 256 | } 257 | 258 | 259 | void xml_close(void) 260 | { 261 | int i, j, at, max; 262 | ip_t *addr; 263 | char name[81]; 264 | 265 | printf("= 0) { 268 | printf(" PSIZE=%d", cpacketsize); 269 | } else { 270 | printf(" PSIZE=rand(%d-%d)",MINPACKET, -cpacketsize); 271 | } 272 | if( bitpattern>=0 ) { 273 | printf(" BITPATTERN=0x%02X", (unsigned char)(bitpattern)); 274 | } else { 275 | printf(" BITPATTERN=rand(0x00-FF)"); 276 | } 277 | printf(" TESTS=%d>\n", MaxPing); 278 | 279 | max = net_max(); 280 | at = net_min(); 281 | for(; at < max; at++) { 282 | addr = net_addr(at); 283 | snprint_addr(name, sizeof(name), addr); 284 | 285 | printf(" \n", at+1, name); 286 | for( i=0; i"); 291 | strcat(name, data_fields[j].format); 292 | strcat(name, "\n"); 293 | /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ 294 | if( index( data_fields[j].format, 'f' ) ) { 295 | printf( name, 296 | data_fields[j].title, 297 | data_fields[j].net_xxx(at) /1000.0, 298 | data_fields[j].title ); 299 | } else { 300 | printf( name, 301 | data_fields[j].title, 302 | data_fields[j].net_xxx(at), 303 | data_fields[j].title ); 304 | } 305 | } 306 | printf(" \n"); 307 | } 308 | printf("\n"); 309 | } 310 | 311 | 312 | void csv_open(void) 313 | { 314 | } 315 | 316 | void csv_close(time_t now) 317 | { 318 | int i, j, at, max; 319 | ip_t *addr; 320 | char name[81]; 321 | 322 | for( i=0; i 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "mtr.h" 33 | #include "dns.h" 34 | #include "net.h" 35 | #include "asn.h" 36 | #include "display.h" 37 | 38 | extern int Interactive; 39 | extern int MaxPing; 40 | extern int ForceMaxPing; 41 | extern float WaitTime; 42 | double dnsinterval; 43 | extern int mtrtype; 44 | extern int display_mode_max; 45 | 46 | static struct timeval intervaltime; 47 | int display_offset = 0; 48 | 49 | fd_set tcp_fds; 50 | int maxfd; 51 | 52 | #define GRACETIME (5 * 1000*1000) 53 | 54 | void select_loop(void) { 55 | fd_set readfd; 56 | fd_set writefd, *p_writefd = NULL; 57 | int anyset = 0; 58 | int dnsfd, netfd; 59 | #ifdef ENABLE_IPV6 60 | int dnsfd6; 61 | #endif 62 | int NumPing = 0; 63 | int paused = 0; 64 | struct timeval lasttime, thistime, selecttime; 65 | struct timeval startgrace; 66 | int dt; 67 | int rv; 68 | int graceperiod = 0; 69 | 70 | memset(&startgrace, 0, sizeof(startgrace)); 71 | FD_ZERO(&tcp_fds); 72 | gettimeofday(&lasttime, NULL); 73 | 74 | if (mtrtype == IPPROTO_TCP) 75 | p_writefd = &writefd; 76 | 77 | while(1) { 78 | dt = calc_deltatime (WaitTime); 79 | intervaltime.tv_sec = dt / 1000000; 80 | intervaltime.tv_usec = dt % 1000000; 81 | 82 | FD_ZERO(&readfd); 83 | 84 | if(Interactive) { 85 | FD_SET(0, &readfd); 86 | if (maxfd == 0) 87 | maxfd++; 88 | } 89 | 90 | #ifdef ENABLE_IPV6 91 | if (dns) { 92 | dnsfd6 = dns_waitfd6(); 93 | if (dnsfd6 >= 0) { 94 | FD_SET(dnsfd6, &readfd); 95 | if(dnsfd6 >= maxfd) maxfd = dnsfd6 + 1; 96 | } else { 97 | dnsfd6 = 0; 98 | } 99 | } else 100 | dnsfd6 = 0; 101 | #endif 102 | if (dns) { 103 | dnsfd = dns_waitfd(); 104 | FD_SET(dnsfd, &readfd); 105 | if(dnsfd >= maxfd) maxfd = dnsfd + 1; 106 | } else 107 | dnsfd = 0; 108 | 109 | netfd = net_waitfd(); 110 | FD_SET(netfd, &readfd); 111 | if(netfd >= maxfd) maxfd = netfd + 1; 112 | 113 | do { 114 | if(anyset || paused) { 115 | /* Set timeout to 0.1s. 116 | * While this is almost instantaneous for human operators, 117 | * it's slow enough for computers to go do something else; 118 | * this prevents mtr from hogging 100% CPU time on one core. 119 | */ 120 | selecttime.tv_sec = 0; 121 | selecttime.tv_usec = paused?100000:0; 122 | 123 | if (mtrtype == IPPROTO_TCP) 124 | writefd = tcp_fds; 125 | rv = select(maxfd, &readfd, p_writefd, NULL, &selecttime); 126 | 127 | } else { 128 | if(Interactive) display_redraw(); 129 | 130 | gettimeofday(&thistime, NULL); 131 | 132 | if(thistime.tv_sec > lasttime.tv_sec + intervaltime.tv_sec || 133 | (thistime.tv_sec == lasttime.tv_sec + intervaltime.tv_sec && 134 | thistime.tv_usec >= lasttime.tv_usec + intervaltime.tv_usec)) { 135 | lasttime = thistime; 136 | 137 | if (!graceperiod) { 138 | if (NumPing >= MaxPing && (!Interactive || ForceMaxPing)) { 139 | graceperiod = 1; 140 | startgrace = thistime; 141 | } 142 | 143 | /* do not send out batch when we've already initiated grace period */ 144 | if (!graceperiod && net_send_batch()) 145 | NumPing++; 146 | } 147 | } 148 | 149 | if (graceperiod) { 150 | dt = (thistime.tv_usec - startgrace.tv_usec) + 151 | 1000000 * (thistime.tv_sec - startgrace.tv_sec); 152 | if (dt > GRACETIME) 153 | return; 154 | } 155 | 156 | selecttime.tv_usec = (thistime.tv_usec - lasttime.tv_usec); 157 | selecttime.tv_sec = (thistime.tv_sec - lasttime.tv_sec); 158 | if (selecttime.tv_usec < 0) { 159 | --selecttime.tv_sec; 160 | selecttime.tv_usec += 1000000; 161 | } 162 | selecttime.tv_usec = intervaltime.tv_usec - selecttime.tv_usec; 163 | selecttime.tv_sec = intervaltime.tv_sec - selecttime.tv_sec; 164 | if (selecttime.tv_usec < 0) { 165 | --selecttime.tv_sec; 166 | selecttime.tv_usec += 1000000; 167 | } 168 | 169 | if (dns) { 170 | if ((selecttime.tv_sec > (time_t)dnsinterval) || 171 | ((selecttime.tv_sec == (time_t)dnsinterval) && 172 | (selecttime.tv_usec > ((time_t)(dnsinterval * 1000000) % 1000000)))) { 173 | selecttime.tv_sec = (time_t)dnsinterval; 174 | selecttime.tv_usec = (time_t)(dnsinterval * 1000000) % 1000000; 175 | } 176 | } 177 | 178 | if (mtrtype == IPPROTO_TCP) 179 | writefd = tcp_fds; 180 | rv = select(maxfd, &readfd, p_writefd, NULL, &selecttime); 181 | } 182 | } while ((rv < 0) && (errno == EINTR)); 183 | 184 | if (rv < 0) { 185 | perror ("Select failed"); 186 | exit (1); 187 | } 188 | anyset = 0; 189 | 190 | /* Have we got new packets back? */ 191 | if(FD_ISSET(netfd, &readfd)) { 192 | net_process_return(); 193 | anyset = 1; 194 | } 195 | 196 | if (dns) { 197 | /* Handle any pending resolver events */ 198 | dnsinterval = WaitTime; 199 | dns_events(&dnsinterval); 200 | } 201 | 202 | /* Have we finished a nameservice lookup? */ 203 | #ifdef ENABLE_IPV6 204 | if(dns && dnsfd6 && FD_ISSET(dnsfd6, &readfd)) { 205 | dns_ack6(); 206 | anyset = 1; 207 | } 208 | #endif 209 | if(dns && dnsfd && FD_ISSET(dnsfd, &readfd)) { 210 | dns_ack(); 211 | anyset = 1; 212 | } 213 | 214 | /* Has a key been pressed? */ 215 | if(FD_ISSET(0, &readfd)) { 216 | switch (display_keyaction()) { 217 | case ActionQuit: 218 | return; 219 | break; 220 | case ActionReset: 221 | net_reset(); 222 | break; 223 | case ActionDisplay: 224 | display_mode = (display_mode + 1) % display_mode_max; 225 | break; 226 | case ActionClear: 227 | display_clear(); 228 | break; 229 | case ActionPause: 230 | paused=1; 231 | break; 232 | case ActionResume: 233 | paused=0; 234 | break; 235 | case ActionMPLS: 236 | enablempls = !enablempls; 237 | display_clear(); 238 | break; 239 | case ActionDNS: 240 | if (dns) { 241 | use_dns = !use_dns; 242 | display_clear(); 243 | } 244 | break; 245 | #ifdef IPINFO 246 | case ActionII: 247 | ii_action(0); 248 | break; 249 | case ActionAS: 250 | ii_action(1); 251 | break; 252 | #endif 253 | case ActionScrollDown: 254 | display_offset += 5; 255 | break; 256 | case ActionScrollUp: 257 | display_offset -= 5; 258 | if (display_offset < 0) { 259 | display_offset = 0; 260 | } 261 | break; 262 | } 263 | anyset = 1; 264 | } 265 | 266 | /* Check for activity on open sockets */ 267 | if (mtrtype == IPPROTO_TCP) 268 | anyset = net_process_tcp_fds(); 269 | } 270 | return; 271 | } 272 | 273 | -------------------------------------------------------------------------------- /select.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | void select_loop(void); 20 | -------------------------------------------------------------------------------- /split.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997 Matt Kimball 4 | 5 | split.c -- raw output (for inclusion in KDE Network Utilities or others 6 | GUI based tools) 7 | Copyright (C) 1998 Bertrand Leconte 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License version 2 as 11 | published by the Free Software Foundation. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with this program; if not, write to the Free Software 20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "mtr.h" 33 | #include "display.h" 34 | #include "dns.h" 35 | #include "asn.h" 36 | 37 | #include "net.h" 38 | #include "split.h" 39 | 40 | #ifdef NO_CURSES 41 | #include 42 | #include 43 | #else 44 | /* Use the curses variant */ 45 | 46 | #if defined(UNICODE) 47 | #define _XOPEN_SOURCE_EXTENDED 48 | #if defined (HAVE_NCURSESW_NCURSES_H) 49 | # include 50 | #elif defined (HAVE_NCURSESW_CURSES_H) 51 | # include 52 | #elif defined (HAVE_CURSES_H) 53 | # include 54 | #else 55 | # error No ncursesw header file available 56 | #endif 57 | #else 58 | 59 | #if defined(HAVE_NCURSES_H) 60 | # include 61 | #elif defined(HAVE_NCURSES_CURSES_H) 62 | # include 63 | #elif defined(HAVE_CURSES_H) 64 | # include 65 | #else 66 | # error No curses header file available 67 | #endif 68 | 69 | #endif 70 | #endif 71 | 72 | #ifdef NO_CURSES 73 | #define SPLIT_PRINT(x) { printf x; printf("\n"); } 74 | #else 75 | // like dns.c:restell() 76 | #define SPLIT_PRINT(x) { printf x; printf("\r\n"); } 77 | #endif 78 | 79 | extern char *Hostname; 80 | extern int WaitTime; 81 | extern int af; 82 | 83 | /* There is 256 hops max in the IP header (coded with a byte) */ 84 | #define MAX_LINE_COUNT 256 85 | #define MAX_LINE_SIZE 512 86 | 87 | char Lines[MAX_LINE_COUNT][MAX_LINE_SIZE]; 88 | int LineCount; 89 | 90 | 91 | #define DEBUG 0 92 | 93 | 94 | void split_redraw(void) 95 | { 96 | int max; 97 | int at; 98 | ip_t *addr, *addrs; 99 | char newLine[MAX_LINE_SIZE]; 100 | int i; 101 | 102 | #if DEBUG 103 | SPLIT_PRINT(("split_redraw()")); 104 | #endif 105 | 106 | /* 107 | * If there is less lines than last time, we delete them 108 | * TEST THIS PLEASE 109 | */ 110 | max = net_max(); 111 | for (i=LineCount; i>max; i--) { 112 | SPLIT_PRINT(("-%d", i)); 113 | LineCount--; 114 | } 115 | 116 | /* 117 | * For each line, we compute the new one and we compare it to the old one 118 | */ 119 | for(at = 0; at < max; at++) { 120 | addr = net_addr(at); 121 | if(addrcmp((void*)addr, (void*)&unspec_addr, af)) { 122 | char str[256], *name; 123 | if (!(name = dns_lookup(addr))) 124 | name = strlongip(addr); 125 | if (show_ips) { 126 | snprintf(str, sizeof(str), "%s\t%s", name, strlongip(addr)); 127 | name = str; 128 | } 129 | /* May be we should test name's length */ 130 | snprintf(newLine, sizeof(newLine), "%s\t%s\t%.1f\t%d\t%d\t%.1f\t%.1f\t%.1f\t%.1f", name, fmt_ipinfo(addr), 131 | net_loss(at)/1000.0, 132 | net_returned(at), net_xmit(at), 133 | net_best(at) /1000.0, net_avg(at)/1000.0, 134 | net_worst(at)/1000.0, 135 | net_stdev(at)/1000.0); 136 | } else { 137 | sprintf(newLine, "???"); 138 | } 139 | 140 | if (strcmp(newLine, Lines[at]) == 0) { 141 | /* The same, so do nothing */ 142 | #if DEBUG 143 | SPLIT_PRINT(("SAME LINE")); 144 | #endif 145 | } else { 146 | SPLIT_PRINT(("%d\t%s", at+1, newLine)); 147 | 148 | if (strcmp(newLine, "???") != 0) { 149 | /* Multi path */ 150 | for (i=0; i < MAXPATH; i++ ) { 151 | addrs = net_addrs(at, i); 152 | if ( addrcmp( (void *) addrs, (void *) addr, af ) == 0 ) continue; 153 | if ( addrcmp( (void *) addrs, (void *) &unspec_addr, af ) == 0 ) break; 154 | char *name; 155 | 156 | if (!(name = dns_lookup(addrs))) 157 | name = strlongip(addrs); 158 | if (show_ips) { 159 | SPLIT_PRINT(("-\t%d\t%d\t%s\t%s\t%s", at+1, i+1, name, strlongip(addrs), fmt_ipinfo(addrs))); 160 | } else { 161 | SPLIT_PRINT(("-\t%d\t%d\t%s\t%s", at+1, i+1, name, fmt_ipinfo(addrs))); 162 | } 163 | } 164 | } 165 | 166 | fflush(stdout); 167 | strcpy(Lines[at], newLine); 168 | if (LineCount < (at+1)) { 169 | LineCount = at+1; 170 | } 171 | } 172 | } 173 | } 174 | 175 | 176 | void split_open(void) 177 | { 178 | int i; 179 | #if DEBUG 180 | printf("split_open()\n"); 181 | #endif 182 | LineCount = -1; 183 | for (i=0; i 0) { 227 | read (0, &c, 1); 228 | } else 229 | return 0; 230 | #else 231 | char c = getch(); 232 | #endif 233 | 234 | #if DEBUG 235 | SPLIT_PRINT(("split_keyaction()")); 236 | #endif 237 | if(tolower((int)c) == 'q') 238 | return ActionQuit; 239 | if(c==3) 240 | return ActionQuit; 241 | if(tolower((int)c) == 'r') 242 | return ActionReset; 243 | 244 | return 0; 245 | } 246 | -------------------------------------------------------------------------------- /split.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | 4 | split.h -- raw output (for inclusion in KDE Network Utilities) 5 | Copyright (C) 1998 Bertrand Leconte 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License version 2 as 9 | published by the Free Software Foundation. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program; if not, write to the Free Software 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 | */ 20 | 21 | /* Prototypes for split.c */ 22 | void split_open(void); 23 | void split_close(void); 24 | void split_redraw(void); 25 | int split_keyaction(void); 26 | -------------------------------------------------------------------------------- /version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 | */ 18 | 19 | #define MTR_VERSION "@VERSION@" 20 | 21 | --------------------------------------------------------------------------------