├── .gitignore ├── .ycm_extra_conf.py ├── AUTHORS ├── CMakeLists.txt ├── LICENSE ├── Makefile.am ├── Makefile.common ├── README.md ├── moduleinfo.h ├── packet-tibia.c ├── plugin.c ├── plugin.rc.in └── screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | .deps/ 2 | .libs/ 3 | e/ 4 | *.lo 5 | *.la 6 | *.o 7 | *.a 8 | *.sw* 9 | *.pyc 10 | -------------------------------------------------------------------------------- /.ycm_extra_conf.py: -------------------------------------------------------------------------------- 1 | # Partially stolen from https://bitbucket.org/mblum/libgp/src/2537ea7329ef/.ycm_extra_conf.py 2 | import os 3 | import ycm_core 4 | 5 | # These are the compilation flags that will be used in case there's no 6 | # compilation database set (by default, one is not set). 7 | # CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR. 8 | flags = [ 9 | '-Wall', 10 | '-Wextra', 11 | '-pedantic', 12 | # THIS IS IMPORTANT! Without a "-std=" flag, clang won't know which 13 | # language to use when compiling headers. So it will guess. Badly. So C++ 14 | # headers will be compiled as C headers. You don't want that so ALWAYS specify 15 | # a "-std=". 16 | # For a C project, you would set this to something like 'c99' instead of 17 | # 'c++11'. 18 | '-std=c89', 19 | # ...and the same thing goes for the magic -x option which specifies the 20 | # language that the files to be compiled are written in. This is mostly 21 | # relevant for c++ headers. 22 | # For a C project, you would set this to 'c' instead of 'c++'. 23 | '-x', 'c', 24 | # This path will only work on OS X, but extra paths that don't exist are not 25 | # harmful 26 | '-DHAVE_CONFIG_H', 27 | '-DHAVE_LIBGCRYPT', 28 | '-isystem', '/usr/local/include', 29 | '-isystem', '/Users/a3f/dl/wireshark', 30 | '-isystem', '/Users/a3f/dl/wireshark/build', 31 | '-isystem', '/opt/local/include/glib-2.0', 32 | '-isystem', '/opt/local/include/glib-2.0/glib', 33 | '-isystem', '/usr/local/Cellar/glib/2.52.0/lib/glib-2.0/include', 34 | '-isystem', '/opt/local/include/glib-2.0', 35 | 36 | '-Wc++98-compat', '-Wc++98-compat-pedantic', 37 | '-Wno-missing-field-initializers', 38 | 39 | '-I', 'include' 40 | '-I', '../include' 41 | '-I.' 42 | ] 43 | 44 | # Set this to the absolute path to the folder (NOT the file!) containing the 45 | # compile_commands.json file to use that instead of 'flags'. See here for 46 | # more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html 47 | # 48 | # Most projects will NOT need to set this to anything; you can just change the 49 | # 'flags' list of compilation flags. Notice that YCM itself uses that approach. 50 | compilation_database_folder = '' 51 | 52 | if compilation_database_folder: 53 | database = ycm_core.CompilationDatabase( compilation_database_folder ) 54 | else: 55 | database = None 56 | 57 | 58 | def DirectoryOfThisScript(): 59 | return os.path.dirname( os.path.abspath( __file__ ) ) 60 | 61 | 62 | def MakeRelativePathsInFlagsAbsolute( flags, working_directory ): 63 | if not working_directory: 64 | return list( flags ) 65 | new_flags = [] 66 | make_next_absolute = False 67 | path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ] 68 | for flag in flags: 69 | new_flag = flag 70 | 71 | if make_next_absolute: 72 | make_next_absolute = False 73 | if not flag.startswith( '/' ): 74 | new_flag = os.path.join( working_directory, flag ) 75 | 76 | for path_flag in path_flags: 77 | if flag == path_flag: 78 | make_next_absolute = True 79 | break 80 | 81 | if flag.startswith( path_flag ): 82 | path = flag[ len( path_flag ): ] 83 | new_flag = path_flag + os.path.join( working_directory, path ) 84 | break 85 | 86 | if new_flag: 87 | new_flags.append( new_flag ) 88 | return new_flags 89 | 90 | 91 | def FlagsForFile( filename ): 92 | if database: 93 | # Bear in mind that compilation_info.compiler_flags_ does NOT return a 94 | # python list, but a "list-like" StringVec object 95 | compilation_info = database.GetCompilationInfoForFile( filename ) 96 | final_flags = MakeRelativePathsInFlagsAbsolute( 97 | compilation_info.compiler_flags_, 98 | compilation_info.compiler_working_dir_ ) 99 | else: 100 | relative_to = DirectoryOfThisScript() 101 | final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to ) 102 | 103 | return { 104 | 'flags': final_flags, 105 | 'do_cache': True 106 | } 107 | 108 | 109 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Author : 2 | Ahmad Fatoum 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # CMakeLists.txt 2 | # 3 | # Wireshark - Network traffic analyzer 4 | # By Gerald Combs 5 | # Copyright 1998 Gerald Combs 6 | # 7 | # This program is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU General Public License 9 | # as published by the Free Software Foundation; either version 2 10 | # of the License, or (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with this program; if not, write to the Free Software 19 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | 22 | include(WiresharkPlugin) 23 | 24 | # Plugin name and version info (major minor micro extra) 25 | set_module_info(tibia 0 0 3 0) 26 | 27 | set(DISSECTOR_SRC 28 | packet-tibia.c 29 | ) 30 | 31 | set(PLUGIN_FILES 32 | plugin.c 33 | ${DISSECTOR_SRC} 34 | ) 35 | 36 | set(CLEAN_FILES 37 | ${PLUGIN_FILES} 38 | ) 39 | 40 | if (WERROR_COMMON_FLAGS) 41 | set_source_files_properties( 42 | ${CLEAN_FILES} 43 | PROPERTIES 44 | COMPILE_FLAGS ${WERROR_COMMON_FLAGS} 45 | ) 46 | endif() 47 | 48 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}) 49 | 50 | register_dissector_files(plugin.c 51 | plugin 52 | ${DISSECTOR_SRC} 53 | ) 54 | 55 | add_plugin_library(tibia) 56 | 57 | install(TARGETS tibia 58 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/${CPACK_PACKAGE_NAME}/plugins/${CPACK_PACKAGE_VERSION} NAMELINK_SKIP 59 | RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}/${CPACK_PACKAGE_NAME}/plugins/${CPACK_PACKAGE_VERSION} 60 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/${CPACK_PACKAGE_NAME}/plugins/${CPACK_PACKAGE_VERSION} 61 | ) 62 | file(GLOB DISSECTOR_HEADERS RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.h") 63 | CHECKAPI( 64 | NAME 65 | tibia 66 | SWITCHES 67 | -g abort -g termoutput -build 68 | SOURCES 69 | ${DISSECTOR_SRC} 70 | ${DISSECTOR_HEADERS} 71 | ) 72 | 73 | # 74 | # Editor modelines - https://www.wireshark.org/tools/modelines.html 75 | # 76 | # Local variables: 77 | # c-basic-offset: 4 78 | # tab-width: 4 79 | # indent-tabs-mode: nil 80 | # End: 81 | # 82 | # vi: set shiftwidth=4 tabstop=4 expandtab: 83 | # :indentSize=4:tabSize=4:noTabs=true: 84 | # 85 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Makefile.am 2 | # Automake file for Tibia plugin 3 | # 4 | # Wireshark - Network traffic analyzer 5 | # By Gerald Combs 6 | # Copyright 1998 Gerald Combs 7 | # 8 | # This program is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU General Public License 10 | # as published by the Free Software Foundation; either version 2 11 | # of the License, or (at your option) any later version. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | # 22 | 23 | include $(top_srcdir)/Makefile.am.inc 24 | include ../Makefile.am.inc 25 | 26 | PLUGIN_NAME = tibia 27 | 28 | AM_CPPFLAGS = -I$(top_srcdir) 29 | 30 | include Makefile.common 31 | 32 | if HAVE_WARNINGS_AS_ERRORS 33 | AM_CFLAGS = -Werror 34 | endif 35 | 36 | plugindir = @plugindir@ 37 | 38 | plugin_LTLIBRARIES = tibia.la 39 | 40 | tibia_la_SOURCES = \ 41 | plugin.c \ 42 | moduleinfo.h \ 43 | $(SRC_FILES) \ 44 | $(HEADER_FILES) 45 | 46 | tibia_la_CPPFLAGS = $(AM_CPPFLAGS) $(PLUGIN_CPPFLAGS) 47 | tibia_la_CFLAGS = $(AM_CFLAGS) $(PLUGIN_CFLAGS) 48 | 49 | tibia_la_LDFLAGS = -module -avoid-version $(PLUGIN_LDFLAGS) 50 | tibia_la_LIBADD = @PLUGIN_LIBS@ 51 | 52 | # Libs must be cleared, or else libtool won't create a shared module. 53 | # If your module needs to be linked against any particular libraries, 54 | # add them here. 55 | LIBS = 56 | 57 | # 58 | # Build plugin.c, which contains the plugin version[] string, a 59 | # function plugin_register() that calls the register routines for all 60 | # protocols, and a function plugin_reg_handoff() that calls the handoff 61 | # registration routines for all protocols. 62 | # 63 | # We do this by scanning sources. If that turns out to be too slow, 64 | # maybe we could just require every .o file to have an register routine 65 | # of a given name (packet-aarp.o -> proto_register_aarp, etc.). 66 | # 67 | # Formatting conventions: The name of the proto_register_* routines an 68 | # proto_reg_handoff_* routines must start in column zero, or must be 69 | # preceded only by "void " starting in column zero, and must not be 70 | # inside #if. 71 | # 72 | # REGISTER_SRC_FILES is assumed to have all the files that need to be scanned. 73 | # 74 | # For some unknown reason, having a big "for" loop in the Makefile 75 | # to scan all the files doesn't work with some "make"s; they seem to 76 | # pass only the first few names in the list to the shell, for some 77 | # reason. 78 | # 79 | # Therefore, we use a script to generate the register.c file. 80 | # The first argument is the directory in which the source files live. 81 | # The second argument is "plugin", to indicate that we should build 82 | # a plugin.c file for a plugin. 83 | # All subsequent arguments are the files to scan. 84 | # 85 | plugin.c: $(REGISTER_SRC_FILES) Makefile.common $(top_srcdir)/tools/make-dissector-reg.py 86 | @echo Making plugin.c 87 | @$(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \ 88 | plugin $(REGISTER_SRC_FILES) 89 | 90 | # 91 | # Currently plugin.c can be included in the distribution because 92 | # we always build all protocol dissectors. We used to have to check 93 | # whether or not to build the snmp dissector. If we again need to 94 | # variably build something, making plugin.c non-portable, uncomment 95 | # the dist-hook line below. 96 | # 97 | # Oh, yuk. We don't want to include "plugin.c" in the distribution, as 98 | # its contents depend on the configuration, and therefore we want it 99 | # to be built when the first "make" is done; however, Automake insists 100 | # on putting *all* source into the distribution. 101 | # 102 | # We work around this by having a "dist-hook" rule that deletes 103 | # "plugin.c", so that "dist" won't pick it up. 104 | # 105 | #dist-hook: 106 | # @rm -f $(distdir)/plugin.c 107 | 108 | CLEANFILES = \ 109 | tibia \ 110 | *~ 111 | 112 | DISTCLEANFILES = \ 113 | $(NODIST_SRC_FILES) \ 114 | $(NODIST_HEADER_FILES) 115 | 116 | MAINTAINERCLEANFILES = \ 117 | Makefile.in \ 118 | $(GENERATED_SRC_FILES) \ 119 | $(GENERATED_HEADER_FILES) \ 120 | plugin.c 121 | 122 | EXTRA_DIST = \ 123 | Makefile.common \ 124 | Makefile.nmake \ 125 | moduleinfo.nmake \ 126 | plugin.rc.in \ 127 | CMakeLists.txt 128 | 129 | checkapi: 130 | $(PERL) $(top_srcdir)/tools/checkAPIs.pl -g abort -g termoutput -build \ 131 | -sourcedir=$(srcdir) \ 132 | $(CLEAN_SRC_FILES) $(CLEAN_HEADER_FILES) 133 | -------------------------------------------------------------------------------- /Makefile.common: -------------------------------------------------------------------------------- 1 | # Makefile.common for Tibia plugin 2 | # Contains the stuff from Makefile.am and Makefile.nmake that is 3 | # a) common to both files and 4 | # b) portable between both files 5 | # 6 | # Wireshark - Network traffic analyzer 7 | # By Gerald Combs 8 | # Copyright 1998 Gerald Combs 9 | # 10 | # This program is free software; you can redistribute it and/or 11 | # modify it under the terms of the GNU General Public License 12 | # as published by the Free Software Foundation; either version 2 13 | # of the License, or (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | 24 | # the name of the plugin 25 | PLUGIN_NAME = tibia 26 | 27 | # Non-generated sources to be scanned for registration routines 28 | NONGENERATED_REGISTER_C_FILES = \ 29 | packet-tibia.c 30 | 31 | # Non-generated sources 32 | NONGENERATED_C_FILES = \ 33 | $(NONGENERATED_REGISTER_C_FILES) \ 34 | rsa.c \ 35 | xtea.c 36 | 37 | # Headers. 38 | CLEAN_HEADER_FILES = 39 | 40 | 41 | HEADER_FILES = \ 42 | $(CLEAN_HEADER_FILES) 43 | 44 | include ../Makefile.common.inc 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # This is outdated. The most recent version is now in upstream Wireshark 2 | 3 | 4 | This dissector was submitted and [accepted](https://code.wireshark.org/review/#/c/23055/) as built-in dissector for [Wireshark](https://wireshark.org) and is shipped with Wireshark >=2.6.0. 5 | 6 | The dissector was added in these two commits: 7 | 8 | * [Add Tibia login protocol dissector](https://github.com/wireshark/wireshark/commit/6a67ba5677b28d8ce4e8b775ee93573297784e0a) 9 | * [Add basic Tibia game protocol dissection](https://github.com/wireshark/wireshark/commit/62c9a8a865779299d5e06cb929680e4bba92d4e7) 10 | 11 | One commit errornously states 11.42 compatibility. This is not (yet) the case. 12 | 13 | ## Tibia Wireshark Dissector 14 | 15 | ![screenshot][macos-screenshot] 16 | 17 | Tibia is a MMORPG developed by Cipsoft GmbH. OTServ is the open-source implementation of the game server. 18 | 19 | This Wireshark dissector decodes the game's communication protocol. It supports all versions from Tibia 7.0 up to Tibia 11.00 (2001-2016). 20 | 21 | Newer versions of the protocol use RSA/XTEA in order to provide a secure communication channel. 22 | In order to dissect packets on these versions, the symmetric (XTEA) key need be provided manually via the preferences Dialog. 23 | In case the private key is provided, Login packets will be decoded to acquire the XTEA key. 24 | OTServ's private key is included by default, so decoding most OTServ traffic should work out of the box. 25 | 26 | Game protocol support is quite incomplete, but it should be able to decrypt all Tibia packets from Tibia 7.00 up. 27 | 28 | ## Long Version 29 | 30 | Tibia (https://tibia.com) is a Massively Multiplayer Online Role-Playing 31 | Game (MMORPG) by Cipsoft GmbH. 32 | 33 | Three official clients exist: The current Qt-based 11.0+ client, 34 | the old C++ client used from Tibia 7.0 till 10.99 and the Flash client. 35 | The latter two are being phased out. They use the same protocol, 36 | except that the session key for the Flash client is transported alongside 37 | the character list over HTTPS. It's possible this is done in the same manner 38 | as in the native client from 10.74 up. We don't support the Flash client. 39 | 40 | The dissector supports Tibia versions from 7.0 (2001) till 41 | 11.00 (2016-10-12). Tibia has an active open source server emulator 42 | community (OTServ) that still makes use of older versions and surpasses 43 | the official servers in popularity, therefore compatibility with older 44 | protocol iterations should be maintained. 45 | 46 | Transport is over TCP, with recent versions encrypting player interaction 47 | with XTEA. Authentication and key exchange is done with a hard-coded 48 | RSA public key in the client. 49 | 50 | Two protocols are dissected: The Tibia login protocol and the Tibia game 51 | protocol. Traditionally, login servers were stateless and only responsible 52 | for providing the addresses of the game servers alongside the character 53 | list upon successful authentication. Then a new authentication request 54 | (this time with character selection) is sent to the game server. 55 | That way, a client who knows the game server address can very well skip 56 | the login server entirely. Starting with 10.61, this is no longer possible, 57 | as the login server provides a session key that needs to be sent to the 58 | game server. 59 | 60 | Starting with Tibia 7.61, login server requests can't be reliably 61 | differentiated from game server requests. Therefore we apply some heuristics 62 | to classify packets. 63 | 64 | Starting with Tibia 11.01, a web service takes the role of the login server. 65 | Starting with Tibia 11.11, the Adler32 checksum was replaced by a 32-bit 66 | sequence number. The most significant bit indicates whether the packet was 67 | DEFLATE-compressed. These features are not yet supported. 68 | 69 | Packets from and to the game server contain commands. Commands are 70 | identified by the first octet and are variable in length. The dissector has 71 | most command names hard-coded. However, a complete implementation of the 72 | game protocol is unlikely. 73 | 74 | The RSA private key usually used by OTServ is hard-coded in. Server 75 | administrators may add their own private key in PEM or PKCS#12 format over 76 | an UAT. For servers where the private key is indeed private (like 77 | for official servers), the symmetric XTEA key (retrievable by memory 78 | peeking or MitM) may be provided to the dissector via UAT. 79 | 80 | Unsurprisingly, no official specification of the protocol exist, following 81 | resources have been written by the community: 82 | 83 | - OTServ: Community effort to replicate a Tibia Server. 84 | - Outcast: A Tibia client implementation of the game protocol as of 2006. 85 | Comes with a PDF spec written by Khaos 86 | - TibiaAPI: Bot framework, containing a listing of commands as of 2009 87 | - TFS: OTServ-Fork which is kept up-to-date with most of the official protocol 88 | - otclient: Open Source implementation of an up-to-date Tibia client 89 | 90 | An official slide set by Cipsoft detailing the architecture of Tibia 91 | from Game Developers Conference Europe 2011 is also available: 92 | http://www.gdcvault.com/play/1014908/Inside-Tibia-The-Technical-Infrastructure 93 | 94 | The login protocol, as implemented here, has been inferred from network 95 | footage and game client execution traces and was written from scratch. 96 | The listing of game protocol commands were taken from TibiaAPI and Khaos' spec 97 | No code of Cipsoft GmbH was used. 98 | 99 | Tibia is a registered trademark of Cipsoft GmbH. 100 | 101 | 102 | [macos-screenshot]: https://github.com/a3f/Tibia-Wireshark-Plugin/blob/master/screenshot.png 103 | 104 | -------------------------------------------------------------------------------- /moduleinfo.h: -------------------------------------------------------------------------------- 1 | /* moduleinfo.h 2 | * 3 | * Module info header for wireshark plugins. 4 | * 5 | * Wireshark - Network traffic analyzer 6 | * By Gerald Combs 7 | * Copyright 1998 Gerald Combs 8 | * 9 | * This program is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU General Public License 11 | * as published by the Free Software Foundation; either version 2 12 | * of the License, or (at your option) any later version. 13 | * 14 | * This program is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with this program; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | */ 23 | 24 | /* Included *after* config.h, in order to re-define these macros */ 25 | 26 | #ifdef PACKAGE 27 | #undef PACKAGE 28 | #endif 29 | 30 | /* Name of package */ 31 | #define PACKAGE "tibia" 32 | 33 | 34 | #ifdef VERSION 35 | #undef VERSION 36 | #endif 37 | 38 | /* Version number of package */ 39 | #define VERSION "0.0.4" 40 | 41 | -------------------------------------------------------------------------------- /packet-tibia.c: -------------------------------------------------------------------------------- 1 | /* packet-tibia.c 2 | * Routines for Tibia/OTServ login and game protocol dissection 3 | * 4 | * Copyright 2017, Ahmad Fatoum 5 | * 6 | * A dissector for: 7 | * Wireshark - Network traffic analyzer 8 | * By Gerald Combs 9 | * Copyright 1998 Gerald Combs 10 | * 11 | * This program is free software; you can redistribute it and/or 12 | * modify it under the terms of the GNU General Public License 13 | * as published by the Free Software Foundation; either version 2 14 | * of the License, or (at your option) any later version. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program; if not, write to the Free Software 23 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 24 | */ 25 | 26 | 27 | /* Tibia (https://tibia.com) is a Massively Multiplayer Online Role-Playing 28 | * Game (MMORPG) by Cipsoft GmbH. 29 | * 30 | * Three official clients exist: The current Qt-based 11.0+ client, 31 | * the old C++ client used from Tibia 7.0 till 10.99 and the Flash client. 32 | * The latter two are being phased out. They use the same protocol, 33 | * except that the session key for the Flash client is transported alongside 34 | * the character list over HTTPS. It's possible this is done in the same manner 35 | * as in the native client from 10.74 up. We don't support the Flash client. 36 | * 37 | * The dissector supports Tibia versions from 7.0 (2001) till 38 | * 11.00 (2016-10-12). Tibia has an active open source server emulator 39 | * community (OTServ) that still makes use of older versions and surpasses 40 | * the official servers in popularity, therefore compatibility with older 41 | * protocol iterations should be maintained. 42 | * 43 | * Transport is over TCP, with recent versions encrypting player interaction 44 | * with XTEA. Authentication and key exchange is done with a hard-coded 45 | * RSA public key in the client. 46 | * 47 | * Two protocols are dissected: The Tibia login protocol and the Tibia game 48 | * protocol. Traditionally, login servers were stateless and only responsible 49 | * for providing the addresses of the game servers alongside the character 50 | * list upon successful authentication. Then a new authentication request 51 | * (this time with character selection) is sent to the game server. 52 | * That way, a client who knows the game server address can very well skip 53 | * the login server entirely. Starting with 10.61, this is no longer possible, 54 | * as the login server provides a session key that needs to be sent to the 55 | * game server. 56 | * 57 | * Starting with Tibia 7.61, login server requests can't be reliably 58 | * differentiated from game server requests. Therefore we apply some heuristics 59 | * to classify packets. 60 | * 61 | * Starting with Tibia 11.01, a web service takes the role of the login server. 62 | * Starting with Tibia 11.11, the Adler32 checksum was replaced by a 32-bit 63 | * sequence number. The most significant bit indicates whether the packet was 64 | * DEFLATE-compressed. These features are not yet supported. 65 | * 66 | * Packets from and to the game server contain commands. Commands are 67 | * identified by the first octet and are variable in length. The dissector has 68 | * most command names hard-coded. However, a complete implementation of the 69 | * game protocol is unlikely. 70 | * 71 | * The RSA private key usually used by OTServ is hard-coded in. Server 72 | * administrators may add their own private key in PEM or PKCS#12 format over 73 | * an UAT. For servers where the private key is indeed private (like 74 | * for official servers), the symmetric XTEA key (retrievable by memory 75 | * peeking or MitM) may be provided to the dissector via UAT. 76 | * 77 | * Unsurprisingly, no official specification of the protocol exist, following 78 | * resources have been written by the community: 79 | * 80 | * - OTServ: Community effort to replicate a Tibia Server. 81 | * - Outcast: A Tibia client implementation of the game protocol as of 2006. 82 | * Comes with a PDF spec written by Khaos 83 | * - TibiaAPI: Bot framework, containing a listing of commands as of 2009 84 | * - TFS: OTServ-Fork which is kept up-to-date with most of the official protocol 85 | * - otclient: Open Source implementation of an up-to-date Tibia client 86 | * 87 | * An official slide set by Cipsoft detailing the architecture of Tibia 88 | * from Game Developers Conference Europe 2011 is also available: 89 | * http://www.gdcvault.com/play/1014908/Inside-Tibia-The-Technical-Infrastructure 90 | * 91 | * The login protocol, as implemented here, has been inferred from network 92 | * footage and game client execution traces and was written from scratch. 93 | * The listing of game protocol commands were taken from TibiaAPI and Khaos' spec 94 | * No code of Cipsoft GmbH was used. 95 | * 96 | * Tibia is a registered trademark of Cipsoft GmbH. 97 | */ 98 | 99 | #include "config.h" 100 | #include 101 | #include "packet-tcp.h" 102 | #include 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | #include 110 | #include 111 | #include 112 | #include 113 | #include 114 | #include 115 | #include 116 | #include 117 | #include 118 | #include 119 | #include 120 | #include 121 | 122 | void proto_register_tibia(void); 123 | void proto_reg_handoff_tibia(void); 124 | 125 | /* preferences */ 126 | static gboolean try_otserv_key = TRUE, 127 | show_char_name = TRUE, 128 | show_acc_info = TRUE, 129 | show_xtea_key = FALSE, 130 | dissect_game_commands = FALSE, 131 | reassemble_tcp_segments = TRUE; 132 | 133 | /* User Access Tables */ 134 | struct rsakeys_assoc { 135 | char *ipaddr; 136 | char *port; 137 | 138 | char *keyfile; 139 | char *password; 140 | }; 141 | 142 | UAT_CSTRING_CB_DEF(rsakeylist_uats, ipaddr, struct rsakeys_assoc) 143 | UAT_CSTRING_CB_DEF(rsakeylist_uats, port, struct rsakeys_assoc) 144 | UAT_FILENAME_CB_DEF(rsakeylist_uats, keyfile, struct rsakeys_assoc) 145 | UAT_CSTRING_CB_DEF(rsakeylist_uats, password, struct rsakeys_assoc) 146 | 147 | #define XTEA_KEY_LEN 16 148 | 149 | struct xteakeys_assoc { 150 | guint32 framenum; 151 | 152 | char *key; 153 | }; 154 | 155 | static void *xteakeys_copy_cb(void *, const void *, size_t); 156 | static void xteakeys_free_cb(void *); 157 | static void xtea_parse_uat(void); 158 | static gboolean xteakeys_uat_fld_key_chk_cb(void *, const char *, guint, const void *, const void *, char **); 159 | 160 | UAT_DEC_CB_DEF(xteakeylist_uats, framenum, struct xteakeys_assoc) 161 | UAT_CSTRING_CB_DEF(xteakeylist_uats, key, struct xteakeys_assoc) 162 | 163 | 164 | #define COND_POISONED 0x1 165 | #define COND_BURNING 0x2 166 | #define COND_ELECTROCUTED 0x4 167 | #define COND_DRUNK 0x8 168 | #define COND_MANASHIELD 0x10 169 | #define COND_PARALYZED 0x20 170 | #define COND_HASTE 0x40 171 | #define COND_BATTLE 0x80 172 | #define COND_DROWNING 0x100 173 | #define COND_FREEZING 0x200 174 | #define COND_DAZZLED 0x400 175 | #define COND_CURSED 0x800 176 | #define COND_BUFF 0x1000 177 | #define COND_PZBLOCK 0x2000 178 | #define COND_PZ 0x4000 179 | #define COND_BLEEDING 0x8000 180 | #define COND_HUNGRY 0x10000 181 | 182 | /* The login server has been traditionally on 7171, 183 | * For OTServ, the game server often listens on the same IP/port, 184 | * but occasionally on 7172. Official Tibia doesn't host login and 185 | * game servers on the same IP address 186 | */ 187 | 188 | #define TIBIA_DEFAULT_TCP_PORT_RANGE "7171,7172" 189 | 190 | static gint proto_tibia = -1; 191 | static uat_t *rsakeys_uat = NULL, *xteakeys_uat = NULL; 192 | static struct rsakeys_assoc *rsakeylist_uats = NULL; 193 | static struct xteakeys_assoc *xteakeylist_uats = NULL; 194 | static guint nrsakeys = 0, nxteakeys = 0; 195 | 196 | static gint hf_tibia_len = -1; 197 | static gint hf_tibia_nonce = -1; 198 | static gint hf_tibia_adler32 = -1; 199 | static gint hf_tibia_adler32_status = -1; 200 | static gint hf_tibia_os = -1; 201 | static gint hf_tibia_proto_version = -1; 202 | static gint hf_tibia_client_version = -1; 203 | static gint hf_tibia_file_versions = -1; 204 | static gint hf_tibia_file_version_spr = -1; 205 | static gint hf_tibia_file_version_dat = -1; 206 | static gint hf_tibia_file_version_pic = -1; 207 | static gint hf_tibia_game_preview_state = -1; 208 | static gint hf_tibia_content_revision = -1; 209 | static gint hf_tibia_undecoded_rsa_data = -1; 210 | static gint hf_tibia_undecoded_xtea_data = -1; 211 | static gint hf_tibia_unknown = -1; 212 | static gint hf_tibia_xtea_key = -1; 213 | static gint hf_tibia_loginflags_gm = -1; 214 | static gint hf_tibia_acc_name = -1; 215 | static gint hf_tibia_acc_number = -1; 216 | static gint hf_tibia_session_key = -1; 217 | static gint hf_tibia_char_name = -1; 218 | static gint hf_tibia_acc_pass = -1; 219 | static gint hf_tibia_char_name_convo = -1; 220 | static gint hf_tibia_acc_name_convo = -1; 221 | static gint hf_tibia_acc_pass_convo = -1; 222 | static gint hf_tibia_session_key_convo = -1; 223 | 224 | static gint hf_tibia_client_info = -1; 225 | static gint hf_tibia_client_locale = -1; 226 | static gint hf_tibia_client_locale_id = -1; 227 | static gint hf_tibia_client_locale_name = -1; 228 | static gint hf_tibia_client_ram = -1; 229 | static gint hf_tibia_client_cpu = -1; 230 | static gint hf_tibia_client_cpu_name = -1; 231 | static gint hf_tibia_client_clock = -1; 232 | static gint hf_tibia_client_clock2 = -1; 233 | static gint hf_tibia_client_gpu = -1; 234 | static gint hf_tibia_client_vram = -1; 235 | static gint hf_tibia_client_resolution = -1; 236 | static gint hf_tibia_client_resolution_x = -1; 237 | static gint hf_tibia_client_resolution_y = -1; 238 | static gint hf_tibia_client_resolution_hz = -1; 239 | 240 | static gint hf_tibia_payload_len = -1; 241 | static gint hf_tibia_loginserv_command = -1; 242 | static gint hf_tibia_gameserv_command = -1; 243 | static gint hf_tibia_client_command = -1; 244 | 245 | static gint hf_tibia_motd = -1; 246 | static gint hf_tibia_dlg_error = -1; 247 | static gint hf_tibia_dlg_info = -1; 248 | 249 | static gint hf_tibia_charlist = -1; 250 | static gint hf_tibia_charlist_length = -1; 251 | static gint hf_tibia_charlist_entry_name = -1; 252 | static gint hf_tibia_charlist_entry_world = -1; 253 | static gint hf_tibia_charlist_entry_ip = -1; 254 | static gint hf_tibia_charlist_entry_port = -1; 255 | 256 | static gint hf_tibia_worldlist = -1; 257 | static gint hf_tibia_worldlist_length = -1; 258 | static gint hf_tibia_worldlist_entry_name = -1; 259 | static gint hf_tibia_worldlist_entry_ip = -1; 260 | static gint hf_tibia_worldlist_entry_port = -1; 261 | static gint hf_tibia_worldlist_entry_preview = -1; 262 | static gint hf_tibia_worldlist_entry_id = -1; 263 | static gint hf_tibia_pacc_days = -1; 264 | 265 | static gint hf_tibia_channel_id = -1; 266 | static gint hf_tibia_channel_name = -1; 267 | 268 | static gint hf_tibia_char_cond = -1; 269 | static gint hf_tibia_char_cond_poisoned = -1; 270 | static gint hf_tibia_char_cond_burning = -1; 271 | static gint hf_tibia_char_cond_electrocuted = -1; 272 | static gint hf_tibia_char_cond_drunk = -1; 273 | static gint hf_tibia_char_cond_manashield = -1; 274 | static gint hf_tibia_char_cond_paralyzed = -1; 275 | static gint hf_tibia_char_cond_haste = -1; 276 | static gint hf_tibia_char_cond_battle = -1; 277 | static gint hf_tibia_char_cond_drowning = -1; 278 | static gint hf_tibia_char_cond_freezing = -1; 279 | static gint hf_tibia_char_cond_dazzled = -1; 280 | static gint hf_tibia_char_cond_cursed = -1; 281 | static gint hf_tibia_char_cond_buff = -1; 282 | static gint hf_tibia_char_cond_pzblock = -1; 283 | static gint hf_tibia_char_cond_pz = -1; 284 | static gint hf_tibia_char_cond_bleeding = -1; 285 | static gint hf_tibia_char_cond_hungry = -1; 286 | 287 | static const int *char_conds[] = { 288 | &hf_tibia_char_cond_poisoned, 289 | &hf_tibia_char_cond_burning, 290 | &hf_tibia_char_cond_electrocuted, 291 | &hf_tibia_char_cond_drunk, 292 | &hf_tibia_char_cond_manashield, 293 | &hf_tibia_char_cond_paralyzed, 294 | &hf_tibia_char_cond_haste, 295 | &hf_tibia_char_cond_battle, 296 | &hf_tibia_char_cond_drowning, 297 | &hf_tibia_char_cond_freezing, 298 | &hf_tibia_char_cond_dazzled, 299 | &hf_tibia_char_cond_cursed, 300 | &hf_tibia_char_cond_buff, 301 | &hf_tibia_char_cond_pzblock, 302 | &hf_tibia_char_cond_pz, 303 | &hf_tibia_char_cond_bleeding, 304 | &hf_tibia_char_cond_hungry, 305 | NULL 306 | }; 307 | 308 | static gint hf_tibia_chat_msg = -1; 309 | static gint hf_tibia_speech_type = -1; 310 | 311 | static gint hf_tibia_coords_x = -1; 312 | static gint hf_tibia_coords_y = -1; 313 | static gint hf_tibia_coords_z = -1; 314 | static gint hf_tibia_coords = -1; 315 | static gint hf_tibia_stackpos = -1; 316 | 317 | #if 0 318 | static gint hf_tibia_item = -1; 319 | #endif 320 | static gint hf_tibia_container = -1; 321 | static gint hf_tibia_container_icon = -1; 322 | static gint hf_tibia_container_slot = -1; 323 | static gint hf_tibia_container_slots = -1; 324 | static gint hf_tibia_inventory = -1; 325 | static gint hf_tibia_vip = -1; 326 | static gint hf_tibia_vip_online = -1; 327 | static gint hf_tibia_player = -1; 328 | static gint hf_tibia_creature = -1; 329 | static gint hf_tibia_creature_health = -1; 330 | static gint hf_tibia_window = -1; 331 | static gint hf_tibia_window_icon = -1; 332 | static gint hf_tibia_window_textlen = -1; 333 | static gint hf_tibia_window_text = -1; 334 | 335 | static gint hf_tibia_light_level = -1; 336 | static gint hf_tibia_light_color = -1; 337 | static gint hf_tibia_magic_effect_id = -1; 338 | static gint hf_tibia_animated_text_color = -1; 339 | static gint hf_tibia_animated_text = -1; 340 | static gint hf_tibia_projectile = -1; 341 | static gint hf_tibia_squarecolor = -1; 342 | static gint hf_tibia_textmsg_class = -1; 343 | static gint hf_tibia_textmsg = -1; 344 | static gint hf_tibia_walk_dir = -1; 345 | 346 | 347 | static gint ett_tibia = -1; 348 | static gint ett_command = -1; 349 | static gint ett_file_versions = -1; 350 | static gint ett_client_info = -1; 351 | static gint ett_locale = -1; 352 | static gint ett_cpu = -1; 353 | static gint ett_resolution = -1; 354 | static gint ett_charlist = -1; 355 | static gint ett_worldlist = -1; 356 | static gint ett_char = -1; 357 | static gint ett_world = -1; 358 | static gint ett_coords = -1; 359 | static gint ett_char_cond = -1; 360 | 361 | 362 | static expert_field ei_xtea_len_toobig = EI_INIT; 363 | static expert_field ei_adler32_checksum_bad = EI_INIT; 364 | static expert_field ei_rsa_plaintext_no_leading_zero = EI_INIT; 365 | static expert_field ei_rsa_ciphertext_too_short = EI_INIT; 366 | static expert_field ei_rsa_decrypt_failed = EI_INIT; 367 | 368 | 369 | struct rsakey { 370 | address addr; 371 | guint16 port; 372 | 373 | gcry_sexp_t privkey; 374 | }; 375 | GHashTable *rsakeys, *xteakeys; 376 | 377 | struct proto_traits { 378 | guint32 adler32:1, rsa:1, compression:1, xtea:1, login_webservice:1, acc_name:1, nonce:1, 379 | extra_gpu_info:1, gmbyte:1, hwinfo:1; 380 | guint32 outfit_addons:1, stamina:1, lvl_on_msg:1; 381 | guint32 ping:1, client_version:1, game_preview:1, auth_token:1, session_key:1; 382 | guint32 game_content_revision:1, worldlist_in_charlist:1; 383 | guint string_enc; 384 | }; 385 | 386 | struct tibia_convo { 387 | guint32 xtea_key[XTEA_KEY_LEN / sizeof (guint32)]; 388 | guint32 xtea_framenum; 389 | const guint8 *acc, *pass, *char_name, *session_key; 390 | struct proto_traits has; 391 | 392 | guint16 proto_version; 393 | guint8 loginserv_is_peer :1; 394 | guint16 clientport; 395 | guint16 servport; 396 | 397 | gcry_sexp_t privkey; 398 | }; 399 | 400 | static struct proto_traits 401 | get_version_traits(guint16 version) 402 | { 403 | struct proto_traits has; 404 | memset(&has, 0, sizeof has); 405 | has.gmbyte = TRUE; /* Not sure when the GM byte first appeared */ 406 | has.string_enc = ENC_ISO_8859_1; 407 | 408 | if (version >= 761) /* 761 was a test client. 770 was the first release */ 409 | has.xtea = has.rsa = TRUE; 410 | if (version >= 780) 411 | has.outfit_addons = has.stamina = has.lvl_on_msg = TRUE; 412 | if (version >= 830) 413 | has.adler32 = has.acc_name = TRUE; 414 | if (version >= 841) 415 | has.hwinfo = has.nonce = TRUE; 416 | if (version >= 953) 417 | has.ping = TRUE; 418 | if (version >= 980) 419 | has.client_version = has.game_preview = TRUE; 420 | if (version >= 1010) 421 | has.worldlist_in_charlist = TRUE; 422 | if (version >= 1061) 423 | has.extra_gpu_info = TRUE; 424 | if (version >= 1071) 425 | has.game_content_revision = TRUE; 426 | if (version >= 1072) 427 | has.auth_token = TRUE; 428 | if (version >= 1074) 429 | has.session_key = TRUE; 430 | if (version >= 1101) 431 | has.login_webservice = TRUE; 432 | if (version >= 1111) { 433 | has.compression = TRUE; /* with DEFLATE */ 434 | has.adler32 = FALSE; 435 | } 436 | #if 0 /* With the legacy client being phased out, maybe Unicode support incoming? */ 437 | if (version >= 11xy) 438 | has.string_enc = ENC_UTF_8; 439 | #endif 440 | 441 | return has; 442 | } 443 | 444 | static guint16 445 | get_version_get_charlist_packet_size(struct proto_traits *has) 446 | { 447 | guint16 size = 2; 448 | if (has->adler32 || has->compression) 449 | size += 4; 450 | size += 17; 451 | if (has->extra_gpu_info) 452 | size += 222; 453 | if (has->rsa) 454 | size += 128; 455 | 456 | return size; 457 | } 458 | static guint16 459 | get_version_char_login_packet_size(struct proto_traits *has) 460 | { 461 | guint16 size = 2; 462 | if (has->adler32 || has->compression) 463 | size += 4; 464 | size += 5; 465 | if (has->client_version) 466 | size += 4; 467 | if (has->game_content_revision) 468 | size += 2; 469 | if (has->game_preview) 470 | size += 1; 471 | if (has->rsa) 472 | size += 128; 473 | 474 | return size; 475 | } 476 | 477 | 478 | #define XTEA_FROM_UAT 0 479 | #define XTEA_UNKNOWN 0xFFFFFFFF 480 | 481 | static struct tibia_convo * 482 | tibia_get_convo(packet_info *pinfo) 483 | { 484 | conversation_t *epan_conversation = find_or_create_conversation(pinfo); 485 | 486 | struct tibia_convo *convo = (struct tibia_convo*)conversation_get_proto_data(epan_conversation, proto_tibia); 487 | 488 | if (!convo) { 489 | struct rsakey rsa_key; 490 | convo = wmem_new0(wmem_file_scope(), struct tibia_convo); 491 | 492 | /* FIXME there gotta be a cleaner way... */ 493 | if (pinfo->srcport >= 0xC000) { 494 | convo->clientport = pinfo->srcport; 495 | 496 | convo->servport = pinfo->destport; 497 | rsa_key.addr = pinfo->dst; 498 | } else { 499 | convo->clientport = pinfo->destport; 500 | 501 | convo->servport = pinfo->srcport; 502 | rsa_key.addr = pinfo->src; 503 | } 504 | rsa_key.port = convo->servport; 505 | convo->privkey = (gcry_sexp_t)g_hash_table_lookup(rsakeys, &rsa_key); 506 | convo->xtea_framenum = XTEA_UNKNOWN; 507 | 508 | conversation_add_proto_data(epan_conversation, proto_tibia, (void *)convo); 509 | } 510 | 511 | if (convo->xtea_framenum == XTEA_UNKNOWN) { 512 | guint8 *xtea_key = (guint8*)g_hash_table_lookup(xteakeys, GUINT_TO_POINTER(pinfo->num)); 513 | if (xtea_key) { 514 | memcpy(convo->xtea_key, xtea_key, XTEA_KEY_LEN); 515 | convo->xtea_framenum = XTEA_FROM_UAT; 516 | } 517 | } 518 | 519 | return convo; 520 | } 521 | 522 | static guint32 523 | ipv4tonl(const char *str) 524 | { 525 | guint32 ipaddr = 0; 526 | for (int octet = 0; octet < 4; octet++) { 527 | ws_strtou8(str, &str, &((guint8*)&ipaddr)[octet]); 528 | str++; 529 | } 530 | return ipaddr; 531 | } 532 | 533 | static void rsakey_free(void *_rsakey); 534 | 535 | static void 536 | register_gameserv_addr(struct tibia_convo *convo, guint32 ipaddr, guint16 port) 537 | { 538 | /* Game servers in the list inherit the same RSA key as the login server */ 539 | if (convo->has.rsa) { 540 | struct rsakey *entry = g_new(struct rsakey, 1); 541 | alloc_address_wmem(NULL, &entry->addr, AT_IPv4, sizeof ipaddr, &ipaddr); 542 | entry->port = port; 543 | entry->privkey = NULL; 544 | if (!g_hash_table_contains(rsakeys, entry)) { 545 | entry->privkey = convo->privkey; 546 | g_hash_table_insert(rsakeys, entry, entry->privkey); 547 | } else { 548 | rsakey_free(entry); 549 | } 550 | } 551 | 552 | /* TODO Mark all communication with the IP/Port pair above 553 | * as Tibia communication. How? 554 | */ 555 | } 556 | 557 | static gcry_sexp_t otserv_key; 558 | static gcry_sexp_t 559 | convo_get_privkey(struct tibia_convo *convo) 560 | { 561 | return convo->privkey ? convo->privkey 562 | : try_otserv_key ? otserv_key 563 | : NULL; 564 | } 565 | 566 | enum client_cmd { 567 | /* from TibiaAPI */ 568 | C_GET_CHARLIST = 0x01, 569 | C_LOGIN_CHAR = 0x0A, 570 | C_LOGOUT = 0x14, /* I think this is a 7.7+ thing */ 571 | C_PONG = 0x1E, 572 | 573 | C_AUTO_WALK = 0x64, 574 | C_GO_NORTH = 0x65, 575 | C_GO_EAST = 0x66, 576 | C_GO_SOUTH = 0x67, 577 | C_GO_WEST = 0x68, 578 | C_AUTO_WALK_CANCEL = 0x69, 579 | C_GO_NE = 0x6A, 580 | C_GO_SE = 0x6B, 581 | C_GO_SW = 0x6C, 582 | C_GO_NW = 0x6D, 583 | C_TURN_NORTH = 0x6F, 584 | C_TURN_EAST = 0x70, 585 | C_TURN_SOUTH = 0x71, 586 | C_TURN_WEST = 0x72, 587 | C_MOVE_ITEM = 0x78, 588 | C_SHOP_BUY = 0x7A, 589 | C_SHOP_SELL = 0x7B, 590 | C_SHOP_CLOSE = 0x7C, 591 | C_ITEM_USE = 0x82, 592 | C_ITEM_USE_ON = 0x83, 593 | C_ITEM_USE_BATTLELIST = 0x84, 594 | C_ITEM_ROTATE = 0x85, 595 | C_CONTAINER_CLOSE = 0x87, 596 | C_CONTAINER_OPEN_PARENT = 0x88, 597 | C_LOOK_AT = 0x8C, 598 | C_PLAYER_SPEECH = 0x96, 599 | C_CHANNEL_LIST = 0x97, 600 | C_CHANNEL_OPEN = 0x98, 601 | C_CHANNEL_CLOSE = 0x99, 602 | C_PRIVATE_CHANNEL_OPEN = 0x9A, 603 | C_NPC_CHANNEL_CLOSE = 0x9E, 604 | C_FIGHT_MODES = 0xA0, 605 | C_ATTACK = 0xA1, 606 | C_FOLLOW = 0xA2, 607 | C_CANCEL_GO = 0xBE, 608 | C_TILE_UPDATE = 0xC9, 609 | C_CONTAINER_UPDATE = 0xCA, 610 | C_SET_OUTFIT = 0xD3, 611 | C_VIP_ADD = 0xDC, 612 | C_VIP_REMOVE = 0xDD 613 | }; 614 | 615 | static const value_string from_client_packet_types[] = { 616 | { C_GET_CHARLIST, "Charlist request" }, 617 | { C_LOGIN_CHAR, "Character login" }, 618 | 619 | { C_LOGOUT, "Logout" }, 620 | { C_PONG, "Pong" }, 621 | 622 | { C_AUTO_WALK, "Map walk" }, 623 | { C_GO_NORTH, "Go north"}, 624 | { C_GO_EAST, "Go east"}, 625 | { C_GO_SOUTH, "Go south"}, 626 | { C_GO_WEST, "Go west"}, 627 | { C_AUTO_WALK_CANCEL, "Map walk cancel" }, 628 | { C_GO_NE, "Go north-east"}, 629 | { C_GO_SE, "Go south-east"}, 630 | { C_GO_SW, "Go south-west"}, 631 | { C_GO_NW, "Go north-west"}, 632 | 633 | { C_TURN_NORTH, "Turn north" }, 634 | { C_TURN_EAST, "Turn east" }, 635 | { C_TURN_SOUTH, "Turn south" }, 636 | { C_TURN_WEST, "Turn west" }, 637 | { C_MOVE_ITEM, "Move item" }, 638 | { C_SHOP_BUY, "Buy in shop" }, 639 | { C_SHOP_SELL, "Sell in shop" }, 640 | { C_SHOP_CLOSE, "Close shop" }, 641 | { C_ITEM_USE, "Use item" }, 642 | { C_ITEM_USE_ON, "Use item on" }, 643 | { C_ITEM_USE_BATTLELIST, "Use item on battle list" }, 644 | { C_ITEM_ROTATE, "Rotate item" }, 645 | 646 | { C_CONTAINER_CLOSE, "Close container" }, 647 | { C_CONTAINER_OPEN_PARENT, "Open parent container" }, 648 | { C_LOOK_AT, "Look at" }, 649 | { C_PLAYER_SPEECH, "Speech" }, 650 | { C_CHANNEL_LIST, "List channels" }, 651 | { C_CHANNEL_OPEN, "Open public channel" }, 652 | { C_CHANNEL_CLOSE, "close channel" }, 653 | { C_PRIVATE_CHANNEL_OPEN, "Open private channel" }, 654 | { C_NPC_CHANNEL_CLOSE, "Open NPC channel" }, 655 | { C_FIGHT_MODES, "Set fight modes" }, 656 | { C_ATTACK, "Attack" }, 657 | { C_FOLLOW, "Follow" }, 658 | { C_CANCEL_GO, "Cancel go" }, 659 | { C_TILE_UPDATE, "Update tile" }, 660 | { C_CONTAINER_UPDATE, "Update container" }, 661 | { C_SET_OUTFIT, "Set outfit" }, 662 | { C_VIP_ADD, "Add VIP" }, 663 | { C_VIP_REMOVE, "Remove VIP" }, 664 | 665 | { 0, NULL } 666 | }; 667 | 668 | static value_string_ext from_client_packet_types_ext = VALUE_STRING_EXT_INIT(from_client_packet_types); 669 | 670 | enum loginserv_cmd { 671 | LOGINSERV_DLG_ERROR = 0x0A, 672 | LOGINSERV_DLG_ERROR2 = 0x0B, 673 | LOGINSERV_DLG_MOTD = 0x14, 674 | LOGINSERV_SESSION_KEY = 0x28, 675 | LOGINSERV_DLG_CHARLIST = 0x64 676 | }; 677 | 678 | static const value_string from_loginserv_packet_types[] = { 679 | { LOGINSERV_DLG_ERROR, "Error" }, 680 | { LOGINSERV_DLG_ERROR2, "Error" }, 681 | { LOGINSERV_DLG_MOTD, "MOTD" }, 682 | { LOGINSERV_SESSION_KEY, "Session key" }, 683 | { LOGINSERV_DLG_CHARLIST, "Charlist" }, 684 | 685 | { 0, NULL } 686 | }; 687 | 688 | enum gameserv_cmd { 689 | /* Credit to Khaos (OBJECT Networks). Values and comments extracted from PDF table */ 690 | S_MAPINIT = 0x0A, /* Long playerCreatureId Int unknownU16 (Byte reportBugs?) */ 691 | S_GMACTIONS = 0x0B, /* Used to be 32 unknown bytes, but with GMs removed it might not be in use anymore */ 692 | S_DLG_ERROR = 0x14, /* String errorMessage */ 693 | S_DLG_INFO = 0x15, 694 | S_DLG_TOOMANYPLAYERS = 0x16, 695 | S_PING = 0x1E, 696 | S_NONCE = 0x1F, 697 | S_PLAYERLOC = 0x64, /* Coord pos */ 698 | S_GO_NORTH = 0x65, /* MapDescription (18,1) */ 699 | S_GO_EAST = 0x66, /* MapDescription (1,14) */ 700 | S_GO_SOUTH = 0x67, /* MapDescription (18,1) */ 701 | S_GO_WEST = 0x68, /* MapDescription (1,14) */ 702 | S_TILEUPDATE = 0x69, /* Coord pos TileDescription td */ 703 | S_ADDITEM = 0x6a, /* Coord pos ThingDescription thing */ 704 | S_REPLACEITEM = 0x6b, /* Coord pos Byte stackpos ThingDescription thing */ 705 | S_REMOVEITEM = 0x6c, /* Coord pos Byte stackpos */ 706 | S_MOVE_THING = 0x6d, 707 | S_CONTAINER = 0x6e, /* Byte index Short containerIcon Byte slotCount ThingDescription item */ 708 | S_CONTAINERCLOSE = 0x6f, /* Byte index */ 709 | S_ADDITEMCONTAINER = 0x70, /* Byte index ThingDescription itm */ 710 | S_TRANSFORMITEMCONTAINER = 0x71, /* Byte index Byte slot */ 711 | S_REMOVEITEMCONTAINER = 0x72, /* Byte index Byte slot */ 712 | S_INVENTORYEMPTY = 0x78, /* Byte invSlot */ 713 | S_INVENTORYITEM = 0x79, /* Byte invSlot ThingDescription itm */ 714 | S_TRADEREQ = 0x7d, /* String otherperson Byte slotCount ThingDescription itm */ 715 | S_TRADEACK = 0x7e, /* String otherperson Byte slotCount ThingDescription itm */ 716 | S_TRADECLOSE = 0x7f, 717 | S_LIGHTLEVEL = 0x82, /* Byte lightlevel Byte lightcolor */ 718 | S_MAGIC_EFFECT = 0x83, 719 | S_ANIMATEDTEXT = 0x84, /* Coord pos Byte color String message */ 720 | S_DISTANCESHOT = 0x85, /* Coord pos1 Byte stackposition Coord pos2 */ 721 | S_CREATURESQUARE = 0x86, /* Long creatureid Byte squarecolor */ 722 | S_CREATURE_HEALTH = 0x8C, 723 | S_CREATURELIGHT = 0x8d, /* Long creatureid Byte ? Byte ? */ 724 | S_SETOUTFIT = 0x8e, /* Long creatureid Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType // can extended look go here too? */ 725 | S_CREATURESPEED = 0x8f, /* YIKES! I didnt handle this! */ 726 | S_TEXTWINDOW = 0x96, /* Long windowId Byte icon Byte maxlength String message */ 727 | S_STATUSMSG = 0xA0, /* Status status */ 728 | S_SKILLS = 0xA1, /* Skills skills */ 729 | S_PLAYER_CONDITION = 0xA2, 730 | S_CANCELATTACK = 0xA3, 731 | S_SPEAK = 0xAA, 732 | S_CHANNELSDIALOG = 0xAB, /* Byte channelCount (Int channelId String channelName) */ 733 | S_CHANNEL_OPEN = 0xAC, 734 | S_OPENPRIV = 0xAD, /* String playerName */ 735 | S_TEXTMESSAGE = 0xB4, /* Byte msgClass String string */ 736 | S_CANCELWALK = 0xB5, /* Byte direction */ 737 | S_FLOORUP = 0xBE, /* Advanced topic; read separate text */ 738 | S_FLOORDOWN = 0xBF, /* Advanced topic; read separate text */ 739 | S_OUTFITLIST = 0xC8, /* Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType Byte firstModel Byte lastModel */ 740 | S_VIPADD = 0xD2, /* long guid string name byte isonline */ 741 | S_VIPLOGIN = 0xD3, /* long guid */ 742 | S_VIPLOGOUT = 0xD4 /* long guid*/ 743 | }; 744 | static const value_string from_gameserv_packet_types[] = { 745 | 746 | { S_MAPINIT, "Initialize map" }, 747 | { S_GMACTIONS, "GM actions" }, 748 | { S_DLG_ERROR, "Error" }, 749 | { S_DLG_INFO, "Info" }, 750 | { S_DLG_TOOMANYPLAYERS, "Too many players" }, 751 | { S_PING, "Ping" }, 752 | { S_NONCE, "Nonce" }, 753 | { S_PLAYERLOC, "Set player location" }, 754 | { S_GO_NORTH, "Go north" }, 755 | { S_GO_EAST, "Go east" }, 756 | { S_GO_SOUTH, "Go south" }, 757 | { S_GO_WEST, "Go west" }, 758 | { S_TILEUPDATE, "Update tile" }, 759 | { S_ADDITEM, "Add item" }, 760 | { S_REPLACEITEM, "Replace item" }, 761 | { S_REMOVEITEM, "Remove item" }, 762 | { S_MOVE_THING, "Move thing" }, 763 | { S_CONTAINER, "Open container" }, 764 | { S_CONTAINERCLOSE, "Close container" }, 765 | 766 | { S_ADDITEMCONTAINER, "Add item in container" }, 767 | { S_TRANSFORMITEMCONTAINER, "Transform item in container" }, 768 | { S_REMOVEITEMCONTAINER, "Remove item in container" }, 769 | 770 | { S_INVENTORYEMPTY, "Inventory empty" }, 771 | { S_INVENTORYITEM, "Inventory item" }, 772 | { S_TRADEREQ, "Trade request" }, 773 | { S_TRADEACK, "Trade acknowledge" }, 774 | { S_TRADECLOSE, "Trade over" }, 775 | { S_LIGHTLEVEL, "Light level" }, 776 | { S_MAGIC_EFFECT, "Magic effect" }, 777 | { S_ANIMATEDTEXT, "Animated text" }, 778 | { S_DISTANCESHOT, "Distance shot" }, 779 | { S_CREATURESQUARE, "Creature square" }, 780 | { S_CREATURE_HEALTH, "Creature health" }, 781 | { S_CREATURELIGHT, "Creature light" }, 782 | { S_SETOUTFIT, "Set outfit" }, 783 | { S_CREATURESPEED, "Set creature speed" }, 784 | { S_TEXTWINDOW, "Text window" }, 785 | { S_STATUSMSG, "Status message" }, 786 | { S_SKILLS, "Skills" }, 787 | { S_PLAYER_CONDITION, "Player condition" }, 788 | { S_CANCELATTACK, "Cancel attack" }, 789 | { S_SPEAK, "Creature speech" }, 790 | { S_CHANNELSDIALOG, "Channels dialog" }, 791 | { S_CHANNEL_OPEN, "Channel open" }, 792 | { S_OPENPRIV, "Private channel open" }, 793 | { S_TEXTMESSAGE, "Text message" }, 794 | { S_CANCELWALK, "Cancel walk" }, 795 | { S_FLOORUP, "Floor +1" }, 796 | { S_FLOORDOWN, "Floor -1" }, 797 | { S_OUTFITLIST, "Outfit list" }, 798 | { S_VIPADD, "Add VIP" }, 799 | { S_VIPLOGIN, "VIP login" }, 800 | { S_VIPLOGOUT, "VIP logout" }, 801 | 802 | { 0, NULL } 803 | }; 804 | 805 | static value_string_ext from_gameserv_packet_types_ext = VALUE_STRING_EXT_INIT(from_gameserv_packet_types); 806 | 807 | static const unit_name_string mb_unit = {"MB", NULL}; 808 | 809 | static int 810 | dissect_loginserv_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, gboolean first_fragment ) 811 | { 812 | ptvcursor_t *ptvc = ptvcursor_new(tree, tvb, offset); 813 | 814 | col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ","); 815 | len += offset; 816 | 817 | if (ptvcursor_current_offset(ptvc) < len) { 818 | for (;;) { 819 | int cmd = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc)); 820 | ptvcursor_add_with_subtree(ptvc, hf_tibia_loginserv_command, 1, convo->has.string_enc, ett_command); 821 | ptvcursor_advance(ptvc, 1); 822 | 823 | switch ((enum loginserv_cmd)cmd) { 824 | case LOGINSERV_DLG_ERROR: 825 | case LOGINSERV_DLG_ERROR2: 826 | ptvcursor_add(ptvc, hf_tibia_dlg_error, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 827 | break; 828 | case LOGINSERV_DLG_MOTD: 829 | ptvcursor_add(ptvc, hf_tibia_motd, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 830 | break; 831 | case LOGINSERV_SESSION_KEY: 832 | ptvcursor_add(ptvc, hf_tibia_session_key, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 833 | break; 834 | case LOGINSERV_DLG_CHARLIST: 835 | if (convo->has.worldlist_in_charlist) { 836 | guint8 world_count = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc)); 837 | ptvcursor_add(ptvc, hf_tibia_worldlist_length, 1, ENC_NA); 838 | /* Empty character list? */ 839 | if (world_count) { 840 | ptvcursor_add_with_subtree(ptvc, hf_tibia_worldlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_worldlist); 841 | while (world_count--) { 842 | proto_item *it = ptvcursor_add(ptvc, hf_tibia_worldlist_entry_id, 1, ENC_NA); 843 | ptvcursor_push_subtree(ptvc, it, ett_world); 844 | 845 | ptvcursor_add(ptvc, hf_tibia_worldlist_entry_name, 2, convo->has.string_enc | ENC_LITTLE_ENDIAN); 846 | guint ipv4addr_len = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc)); 847 | char *ipv4addr_str = (char*)tvb_get_string_enc(wmem_packet_scope(), tvb, ptvcursor_current_offset(ptvc) + 2, ipv4addr_len, ENC_LITTLE_ENDIAN | convo->has.string_enc); 848 | guint32 ipv4addr = ipv4tonl(ipv4addr_str); 849 | ptvcursor_add(ptvc, hf_tibia_worldlist_entry_ip, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 850 | guint16 port = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc)); 851 | ptvcursor_add(ptvc, hf_tibia_worldlist_entry_port, 2, ENC_LITTLE_ENDIAN); 852 | ptvcursor_add(ptvc, hf_tibia_worldlist_entry_preview, 1, ENC_NA); 853 | 854 | ptvcursor_pop_subtree(ptvc); 855 | 856 | register_gameserv_addr(convo, ipv4addr, port); 857 | } 858 | ptvcursor_pop_subtree(ptvc); 859 | } 860 | 861 | guint8 char_count = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc)); 862 | ptvcursor_add(ptvc, hf_tibia_charlist_length, 1, ENC_NA); 863 | if (char_count) { 864 | ptvcursor_add_with_subtree(ptvc, hf_tibia_charlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_charlist); 865 | while (char_count--) { 866 | proto_item *it = ptvcursor_add(ptvc, hf_tibia_worldlist_entry_id, 1, ENC_NA); 867 | ptvcursor_push_subtree(ptvc, it, ett_char); 868 | ptvcursor_add(ptvc, hf_tibia_charlist_entry_name, 2, convo->has.string_enc | ENC_LITTLE_ENDIAN); 869 | 870 | 871 | ptvcursor_pop_subtree(ptvc); 872 | } 873 | ptvcursor_pop_subtree(ptvc); 874 | } 875 | } else { 876 | guint8 char_count = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc)); 877 | ptvcursor_add(ptvc, hf_tibia_charlist_length, 1, ENC_NA); 878 | if (char_count) { 879 | ptvcursor_add_with_subtree(ptvc, hf_tibia_charlist, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_charlist); 880 | 881 | while (char_count--) { 882 | proto_item *it = ptvcursor_add(ptvc, hf_tibia_charlist_entry_name, 2, convo->has.string_enc | ENC_LITTLE_ENDIAN); 883 | ptvcursor_push_subtree(ptvc, it, ett_char); 884 | 885 | ptvcursor_add(ptvc, hf_tibia_charlist_entry_world, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 886 | 887 | guint32 ipv4addr = tvb_get_ipv4(tvb, ptvcursor_current_offset(ptvc)); 888 | ptvcursor_add(ptvc, hf_tibia_charlist_entry_ip, 4, ENC_BIG_ENDIAN); 889 | 890 | guint16 port = tvb_get_letohs(tvb, ptvcursor_current_offset(ptvc)); 891 | ptvcursor_add(ptvc, hf_tibia_charlist_entry_port, 2, ENC_BIG_ENDIAN); 892 | 893 | 894 | ptvcursor_pop_subtree(ptvc); 895 | 896 | register_gameserv_addr(convo, ipv4addr, port); 897 | } 898 | 899 | ptvcursor_pop_subtree(ptvc); 900 | } 901 | 902 | ptvcursor_add(ptvc, hf_tibia_pacc_days, 2, ENC_LITTLE_ENDIAN); 903 | } 904 | break; 905 | default: 906 | offset = ptvcursor_current_offset(ptvc); 907 | call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc)); 908 | ptvcursor_advance(ptvc, len - offset); 909 | } 910 | 911 | ptvcursor_pop_subtree(ptvc); 912 | 913 | col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)", 914 | val_to_str(cmd, from_loginserv_packet_types, "Unknown"), cmd); 915 | 916 | if (ptvcursor_current_offset(ptvc) >= len) 917 | break; 918 | 919 | col_append_str(pinfo->cinfo, COL_INFO, ","); 920 | } 921 | } 922 | 923 | offset = ptvcursor_current_offset(ptvc); 924 | ptvcursor_free(ptvc); 925 | 926 | return offset; 927 | } 928 | 929 | static void 930 | dissect_coord(ptvcursor_t *ptvc, gboolean with_stackpos) 931 | { 932 | tvbuff_t *tvb; 933 | proto_tree *tree; 934 | int offset; 935 | 936 | guint32 x, y, z, stackpos; 937 | proto_item *coords_tuple = ptvcursor_add_with_subtree(ptvc, hf_tibia_coords, SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_coords); 938 | { 939 | tvb = ptvcursor_tvbuff(ptvc); 940 | tree = ptvcursor_tree(ptvc); 941 | offset = ptvcursor_current_offset(ptvc); 942 | 943 | proto_tree_add_item_ret_uint(tree, hf_tibia_coords_x, tvb, offset, 2, ENC_LITTLE_ENDIAN, &x); 944 | offset += 2; 945 | proto_tree_add_item_ret_uint(tree, hf_tibia_coords_y, tvb, offset, 2, ENC_LITTLE_ENDIAN, &y); 946 | offset += 2; 947 | proto_tree_add_item_ret_uint(tree, hf_tibia_coords_z, tvb, offset, 1, ENC_NA, &z); 948 | offset += 1; 949 | 950 | ptvcursor_advance(ptvc, 5); 951 | } 952 | if (with_stackpos) { 953 | proto_tree_add_item_ret_uint(tree, hf_tibia_stackpos, tvb, offset, 1, ENC_NA, &stackpos); 954 | proto_item_set_text(coords_tuple, "Coordinates: (%u, %u, %u)[%u]", x, y, z, stackpos); 955 | ptvcursor_advance(ptvc, 1); 956 | } else { 957 | proto_item_set_text(coords_tuple, "Coordinates: (%u, %u, %u)", x, y, z); 958 | } 959 | 960 | ptvcursor_pop_subtree(ptvc); 961 | } 962 | 963 | 964 | static int 965 | dissect_gameserv_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, gboolean first_fragment) 966 | { 967 | ptvcursor_t *ptvc = ptvcursor_new(tree, tvb, offset); 968 | 969 | col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ","); 970 | len += offset; 971 | 972 | if (ptvcursor_current_offset(ptvc) < len) { 973 | for (;;) { 974 | int cmd = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc)); 975 | ptvcursor_add_with_subtree(ptvc, hf_tibia_gameserv_command, 1, convo->has.string_enc, ett_command); 976 | ptvcursor_advance(ptvc, 1); 977 | 978 | switch ((enum gameserv_cmd)cmd) { 979 | case S_DLG_INFO: 980 | case S_DLG_ERROR: 981 | case S_DLG_TOOMANYPLAYERS: 982 | ptvcursor_add(ptvc, cmd == S_DLG_ERROR ? hf_tibia_dlg_error : hf_tibia_dlg_info, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 983 | break; 984 | case S_GMACTIONS: /* 0x0B, Used to be 32 unknown bytes, but with GMs removed it might not be in use anymore */ 985 | ptvcursor_add(ptvc, hf_tibia_unknown, 32, ENC_NA); 986 | break; 987 | case S_PLAYERLOC: /* 0x64,Coord pos */ 988 | dissect_coord(ptvc, FALSE); 989 | break; 990 | case S_TILEUPDATE: /* 0x69,Coord pos TileDescription td */ 991 | dissect_coord(ptvc, FALSE); 992 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 993 | break; 994 | case S_ADDITEM: /* 0x6a,Coord pos ThingDescription thing */ 995 | dissect_coord(ptvc, FALSE); 996 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 997 | break; 998 | case S_REPLACEITEM: /* 0x6b,Coord pos Byte stackpos ThingDescription thing */ 999 | dissect_coord(ptvc, TRUE); 1000 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 1001 | break; 1002 | case S_REMOVEITEM: /* 0x6c,Coord pos Byte stackpos */ 1003 | dissect_coord(ptvc, TRUE); 1004 | break; 1005 | case S_MOVE_THING: /* 0x6d, */ 1006 | dissect_coord(ptvc, TRUE); 1007 | dissect_coord(ptvc, FALSE); 1008 | break; 1009 | case S_CONTAINER: /* 0x6e,Byte index Short containerIcon Byte slotCount ThingDescription item */ 1010 | ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA); 1011 | ptvcursor_add(ptvc, hf_tibia_container_icon, 2, ENC_LITTLE_ENDIAN); 1012 | ptvcursor_add(ptvc, hf_tibia_container_slots, 2, ENC_LITTLE_ENDIAN); 1013 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 1014 | break; 1015 | case S_CONTAINERCLOSE: /* 0x6f,Byte index */ 1016 | ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA); 1017 | break; 1018 | case S_ADDITEMCONTAINER: /* 0x70,Byte index ThingDescription itm */ 1019 | ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA); 1020 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 1021 | break; 1022 | case S_TRANSFORMITEMCONTAINER:/* 0x71,Byte index Byte slot */ 1023 | ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA); 1024 | ptvcursor_add(ptvc, hf_tibia_container_slot, 1, ENC_NA); 1025 | break; 1026 | case S_REMOVEITEMCONTAINER: /* 0x72,Byte index Byte slot */ 1027 | ptvcursor_add(ptvc, hf_tibia_container, 1, ENC_NA); 1028 | ptvcursor_add(ptvc, hf_tibia_container_slot, 1, ENC_NA); 1029 | break; 1030 | case S_INVENTORYEMPTY: /* 0x78,Byte invSlot */ 1031 | ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA); 1032 | break; 1033 | case S_INVENTORYITEM: /* 0x79,Byte invSlot ThingDescription itm */ 1034 | ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA); 1035 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 1036 | break; 1037 | case S_TRADEREQ: /* 0x7d,String otherperson Byte slotCount ThingDescription itm */ 1038 | ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 1039 | ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA); 1040 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 1041 | break; 1042 | case S_TRADEACK: /* 0x7e,String otherperson Byte slotCount ThingDescription itm */ 1043 | ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 1044 | ptvcursor_add(ptvc, hf_tibia_inventory, 1, ENC_NA); 1045 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 1046 | break; 1047 | 1048 | case S_TRADECLOSE: /* 0x7f, */ 1049 | break; 1050 | case S_LIGHTLEVEL: /* 0x82,Byte lightlevel Byte lightcolor */ 1051 | ptvcursor_add(ptvc, hf_tibia_light_level, 1, ENC_NA); 1052 | ptvcursor_add(ptvc, hf_tibia_light_color, 1, ENC_NA); 1053 | break; 1054 | case S_MAGIC_EFFECT: /* 0x83, */ 1055 | dissect_coord(ptvc, FALSE); 1056 | ptvcursor_add(ptvc, hf_tibia_magic_effect_id, 1, ENC_NA); 1057 | break; 1058 | case S_ANIMATEDTEXT: /* 0x84,Coord pos Byte color String message */ 1059 | dissect_coord(ptvc, FALSE); 1060 | ptvcursor_add(ptvc, hf_tibia_animated_text_color, 1, ENC_NA); 1061 | ptvcursor_add(ptvc, hf_tibia_animated_text, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 1062 | break; 1063 | case S_DISTANCESHOT: /* 0x85,Coord pos1 Byte stackposition Coord pos2 */ 1064 | dissect_coord(ptvc, FALSE); 1065 | ptvcursor_add(ptvc, hf_tibia_projectile, 4, ENC_LITTLE_ENDIAN); 1066 | dissect_coord(ptvc, FALSE); 1067 | break; 1068 | case S_CREATURESQUARE: /* 0x86,Long creatureid Byte squarecolor */ 1069 | ptvcursor_add(ptvc, hf_tibia_creature, 4, ENC_LITTLE_ENDIAN); 1070 | ptvcursor_add(ptvc, hf_tibia_squarecolor, 1, ENC_NA); 1071 | break; 1072 | case S_CREATURE_HEALTH: /* 0x8C, */ 1073 | ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN); 1074 | ptvcursor_add(ptvc, hf_tibia_creature_health, 1, ENC_NA); 1075 | break; 1076 | case S_CREATURELIGHT: /* 0x8d,Long creatureid Byte ? Byte ? */ 1077 | ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN); 1078 | ptvcursor_add(ptvc, hf_tibia_unknown, 2, ENC_NA); 1079 | break; 1080 | case S_SETOUTFIT: /* 0x8e,Long creatureid Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType // can extended look go here too? */ 1081 | ptvcursor_add(ptvc, hf_tibia_creature, 1, ENC_LITTLE_ENDIAN); 1082 | ptvcursor_add(ptvc, hf_tibia_unknown, len - ptvcursor_current_offset(ptvc), ENC_NA); 1083 | break; 1084 | case S_TEXTWINDOW: /* 0x96,Long windowId Byte icon Byte maxlength String message */ 1085 | ptvcursor_add(ptvc, hf_tibia_window, 4, ENC_LITTLE_ENDIAN); 1086 | ptvcursor_add(ptvc, hf_tibia_window_icon, 1, ENC_NA); 1087 | ptvcursor_add(ptvc, hf_tibia_window_textlen, 1, ENC_NA); 1088 | ptvcursor_add(ptvc, hf_tibia_window_text, 1, ENC_LITTLE_ENDIAN | convo->has.string_enc); 1089 | break; 1090 | case S_PLAYER_CONDITION: /* 0xA2, */ 1091 | proto_tree_add_bitmask(ptvcursor_tree(ptvc), ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc), hf_tibia_char_cond, ett_char_cond, char_conds, ENC_LITTLE_ENDIAN); 1092 | ptvcursor_advance(ptvc, sizeof(guint32)); 1093 | break; 1094 | case S_CANCELATTACK: /* 0xA3, */ 1095 | break; 1096 | case S_CHANNEL_OPEN: 1097 | ptvcursor_add(ptvc, hf_tibia_channel_id, 2, ENC_LITTLE_ENDIAN); 1098 | ptvcursor_add(ptvc, hf_tibia_channel_name, 2, ENC_LITTLE_ENDIAN|convo->has.string_enc); 1099 | ptvcursor_add(ptvc, hf_tibia_unknown, 4, ENC_NA); 1100 | break; 1101 | case S_OPENPRIV: /* 0xAD,String playerName */ 1102 | ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 1103 | break; 1104 | case S_TEXTMESSAGE: /* 0xB4,Byte msgClass String string */ 1105 | ptvcursor_add(ptvc, hf_tibia_textmsg_class, 1, ENC_NA); 1106 | ptvcursor_add(ptvc, hf_tibia_textmsg, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 1107 | break; 1108 | case S_CANCELWALK: /* 0xB5,Byte direction */ 1109 | ptvcursor_add(ptvc, hf_tibia_walk_dir, 1, ENC_NA); 1110 | break; 1111 | case S_VIPADD: /* 0xd2,long guid string name byte isonline */ 1112 | ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN); 1113 | ptvcursor_add(ptvc, hf_tibia_player, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc); 1114 | ptvcursor_add(ptvc, hf_tibia_vip_online, 1, ENC_NA); 1115 | break; 1116 | case S_VIPLOGIN: /* 0xd3,long guid */ 1117 | ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN); 1118 | break; 1119 | case S_VIPLOGOUT: /* 0xd4long guid*/ 1120 | ptvcursor_add(ptvc, hf_tibia_vip, 4, ENC_LITTLE_ENDIAN); 1121 | break; 1122 | case S_PING: 1123 | break; 1124 | case S_NONCE: /* 0x1F, */ 1125 | ptvcursor_add(ptvc, hf_tibia_nonce, 5, ENC_NA); 1126 | break; 1127 | 1128 | case S_MAPINIT: /* 0x0A, Long playerCreatureId Int unknownU16 (Byte reportBugs?) */ 1129 | case S_OUTFITLIST: /* 0xC8,Byte lookType Byte headType Byte bodyType Byte legsType Byte feetType Byte firstModel Byte lastModel */ 1130 | /* TODO This changed with mounts and outfit */ 1131 | case S_FLOORUP: /* 0xBE,Advanced topic; read separate text */ 1132 | case S_FLOORDOWN: /* 0xBF,Advanced topic; read separate text */ 1133 | case S_SPEAK: /* 0xAA, */ 1134 | case S_CHANNELSDIALOG: /* 0xAB,Byte channelCount (Int channelId String channelName) */ 1135 | case S_STATUSMSG: /* 0xA0,Status status */ 1136 | case S_SKILLS: /* 0xA1,Skills skills */ 1137 | case S_CREATURESPEED: /* 0x8f,YIKES! I didnt handle this! */ 1138 | case S_GO_NORTH: /* 0x65,MapDescription (18,1) */ 1139 | case S_GO_EAST: /* 0x66,MapDescription (1,14) */ 1140 | case S_GO_SOUTH: /* 0x67,MapDescription (18,1) */ 1141 | case S_GO_WEST: /* 0x68,MapDescription (1,14) */ 1142 | default: 1143 | offset = ptvcursor_current_offset(ptvc); 1144 | call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc)); 1145 | ptvcursor_advance(ptvc, len - offset); 1146 | } 1147 | 1148 | 1149 | ptvcursor_pop_subtree(ptvc); 1150 | 1151 | col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)", 1152 | val_to_str(cmd, from_gameserv_packet_types, "Unknown"), cmd); 1153 | 1154 | if (ptvcursor_current_offset(ptvc) >= len) 1155 | break; 1156 | 1157 | col_append_str(pinfo->cinfo, COL_INFO, ","); 1158 | } 1159 | } 1160 | 1161 | offset = ptvcursor_current_offset(ptvc); 1162 | ptvcursor_free(ptvc); 1163 | 1164 | return offset; 1165 | } 1166 | 1167 | static int 1168 | dissect_client_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, int len, packet_info *pinfo, proto_tree *tree, gboolean first_fragment) 1169 | { 1170 | ptvcursor_t *ptvc = ptvcursor_new(tree, tvb, offset); 1171 | 1172 | col_append_str(pinfo->cinfo, COL_INFO, first_fragment ? " commands:" : ","); 1173 | len += offset; 1174 | 1175 | if (ptvcursor_current_offset(ptvc) < len) { 1176 | for (;;) { 1177 | int cmd = tvb_get_guint8(tvb, ptvcursor_current_offset(ptvc)); 1178 | ptvcursor_add_with_subtree(ptvc, hf_tibia_client_command, 1, convo->has.string_enc, ett_command); 1179 | ptvcursor_advance(ptvc, 1); 1180 | 1181 | switch ((enum client_cmd)cmd) { 1182 | case C_PLAYER_SPEECH: { 1183 | guint8 type = tvb_get_guint8(ptvcursor_tvbuff(ptvc), ptvcursor_current_offset(ptvc)); 1184 | 1185 | ptvcursor_add(ptvc, hf_tibia_speech_type, 1, ENC_NA); 1186 | if (type == 0x7) 1187 | ptvcursor_add(ptvc, hf_tibia_channel_id, 2, ENC_LITTLE_ENDIAN); 1188 | ptvcursor_add(ptvc, hf_tibia_chat_msg, 2, ENC_LITTLE_ENDIAN|convo->has.string_enc); 1189 | } 1190 | break; 1191 | case C_PONG: 1192 | break; 1193 | default: 1194 | offset = ptvcursor_current_offset(ptvc); 1195 | call_data_dissector(tvb_new_subset_length(tvb, offset, len - offset), pinfo, ptvcursor_tree(ptvc)); 1196 | ptvcursor_advance(ptvc, len - offset); 1197 | } 1198 | 1199 | ptvcursor_pop_subtree(ptvc); 1200 | 1201 | col_append_fstr(pinfo->cinfo, COL_INFO, " %s (0x%x)", 1202 | val_to_str(cmd, from_client_packet_types, "Unknown"), cmd); 1203 | 1204 | if (ptvcursor_current_offset(ptvc) >= len) 1205 | break; 1206 | 1207 | col_append_str(pinfo->cinfo, COL_INFO, ","); 1208 | } 1209 | } 1210 | 1211 | offset = ptvcursor_current_offset(ptvc); 1212 | ptvcursor_free(ptvc); 1213 | 1214 | return offset; 1215 | } 1216 | 1217 | static int 1218 | dissect_game_packet(struct tibia_convo *convo, tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, gboolean is_xtea_encrypted, gboolean first_fragment) 1219 | { 1220 | proto_item *ti = NULL; 1221 | int len = tvb_captured_length_remaining(tvb, offset); 1222 | 1223 | if (show_acc_info) { 1224 | if (convo->has.session_key) { 1225 | if (convo->session_key) { 1226 | ti = proto_tree_add_string(tree, hf_tibia_session_key_convo, tvb, offset, 0, (const char*)convo->session_key); 1227 | PROTO_ITEM_SET_GENERATED(ti); 1228 | } 1229 | } else { 1230 | if (convo->acc) { 1231 | ti = proto_tree_add_string(tree, hf_tibia_acc_name_convo, tvb, offset, 0, (const char*)convo->acc); 1232 | PROTO_ITEM_SET_GENERATED(ti); 1233 | } 1234 | 1235 | if (convo->pass) { 1236 | ti = proto_tree_add_string(tree, hf_tibia_acc_pass_convo, tvb, offset, 0, (const char*)convo->pass); 1237 | PROTO_ITEM_SET_GENERATED(ti); 1238 | } 1239 | } 1240 | } 1241 | 1242 | if (show_char_name && convo->char_name) { 1243 | ti = proto_tree_add_string(tree, hf_tibia_char_name_convo, tvb, offset, 0, (const char*)convo->char_name); 1244 | PROTO_ITEM_SET_GENERATED(ti); 1245 | } 1246 | 1247 | if (is_xtea_encrypted) { 1248 | if (pinfo->num > convo->xtea_framenum) { 1249 | if (show_xtea_key && convo->has.xtea) { 1250 | ti = proto_tree_add_bytes_with_length(tree, hf_tibia_xtea_key, tvb, 0, 0, (guint8*)convo->xtea_key, XTEA_KEY_LEN); 1251 | PROTO_ITEM_SET_GENERATED(ti); 1252 | } 1253 | 1254 | int end = offset + len; 1255 | 1256 | if (len % 8 != 0) 1257 | return -1; 1258 | 1259 | guint8 *decrypted_buffer = (guint8*)g_malloc(len); 1260 | 1261 | for (guint8 *dstblock = decrypted_buffer; offset < end; offset += 8) { 1262 | decrypt_xtea_le_ecb(dstblock, tvb_get_ptr(tvb, offset, 8), convo->xtea_key, 32); 1263 | dstblock += 8; 1264 | } 1265 | 1266 | tvb = tvb_new_child_real_data(tvb, decrypted_buffer, len, len); 1267 | tvb_set_free_cb(tvb, g_free); 1268 | add_new_data_source(pinfo, tvb, "Decrypted Game Data"); 1269 | 1270 | offset = 0; 1271 | } else { 1272 | proto_tree_add_item(tree, hf_tibia_undecoded_xtea_data, tvb, offset, len, ENC_NA); 1273 | return offset; 1274 | } 1275 | } 1276 | if (convo->has.xtea) { 1277 | len = tvb_get_letohs(tvb, offset); 1278 | ti = proto_tree_add_item(tree, hf_tibia_payload_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); 1279 | offset += 2; 1280 | if (len > tvb_captured_length_remaining(tvb, offset)) { 1281 | expert_add_info(pinfo, ti, &ei_xtea_len_toobig); 1282 | return offset; 1283 | } 1284 | } 1285 | 1286 | 1287 | if (pinfo->srcport == convo->servport && convo->loginserv_is_peer) 1288 | return dissect_loginserv_packet(convo, tvb, offset, len, pinfo, tree, first_fragment); 1289 | 1290 | if (!dissect_game_commands) { 1291 | call_data_dissector(tvb_new_subset_length(tvb, offset, len), pinfo, tree); 1292 | return offset + len; 1293 | } 1294 | 1295 | if (pinfo->srcport == convo->servport) 1296 | return dissect_gameserv_packet(convo, tvb, offset, len, pinfo, tree, first_fragment); 1297 | else 1298 | return dissect_client_packet(convo, tvb, offset, len, pinfo, tree, first_fragment); 1299 | } 1300 | 1301 | static int 1302 | dissect_tibia(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *fragment_num) 1303 | { 1304 | tvbuff_t *tvb_decrypted = tvb; 1305 | gboolean is_xtea_encrypted = FALSE; 1306 | enum { TIBIA_GAMESERV, TIBIA_LOGINSERV } serv = TIBIA_GAMESERV; 1307 | guint16 plen = tvb_get_letohs(tvb, 0) + sizeof(guint16); 1308 | 1309 | /* if announced length != real length it's not a tibia packet */ 1310 | if (tvb_reported_length_remaining(tvb, 0) != plen) 1311 | return 0; 1312 | 1313 | struct tibia_convo *convo = tibia_get_convo(pinfo); 1314 | 1315 | int offset = 2; 1316 | int a32len = tvb_reported_length_remaining(tvb, offset + 4); 1317 | guint32 packet_cksum = tvb_get_letohl(tvb, offset); 1318 | guint32 computed_cksum = GUINT32_TO_LE(adler32_bytes(tvb_get_ptr(tvb, offset + 4, a32len), a32len)); 1319 | convo->has.adler32 = packet_cksum == computed_cksum; 1320 | if (convo->has.adler32) 1321 | offset += sizeof(guint32); 1322 | 1323 | /* FIXME Tibia >=11.11 has a sequence number instead, this is yet unhandled */ 1324 | 1325 | /* Is it a nonce? */ 1326 | if (tvb_get_letohs(tvb, offset) == plen - offset - sizeof(guint16) 1327 | && tvb_get_guint8(tvb, offset+sizeof(guint16)) == S_NONCE) { 1328 | /* Don't do anything. We'll handle it as unencrypted game command later */ 1329 | } else { 1330 | guint8 cmd; 1331 | guint16 version; 1332 | struct proto_traits version_has; 1333 | cmd = tvb_get_guint8(tvb, offset); 1334 | offset += sizeof(guint8); 1335 | offset += sizeof(guint16); /* OS */ 1336 | version = tvb_get_letohs(tvb, offset); 1337 | version_has = get_version_traits(version); 1338 | 1339 | switch(cmd) { 1340 | case C_GET_CHARLIST: 1341 | if ((700 <= version && version <= 760 && !convo->has.adler32 && 25 <= plen && plen <= 54) 1342 | || get_version_get_charlist_packet_size(&version_has) == plen) { 1343 | serv = TIBIA_LOGINSERV; 1344 | convo->loginserv_is_peer = TRUE; 1345 | } 1346 | break; 1347 | case C_LOGIN_CHAR: 1348 | /* The outcast client I tried, zero-pads the 760 login request. 1349 | * I don't think the Cipsoft client ever did this. 1350 | */ 1351 | if ((700 <= version && version <= 760 && !convo->has.adler32 && 25 <= plen && plen <= 54) 1352 | || get_version_char_login_packet_size(&version_has) == plen) 1353 | serv = TIBIA_LOGINSERV; 1354 | break; 1355 | default: 1356 | is_xtea_encrypted = convo->has.xtea; 1357 | } 1358 | } 1359 | 1360 | 1361 | offset = 0; /* With the version extracted, let's build the tree */ 1362 | 1363 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "Tibia"); 1364 | if (GPOINTER_TO_UINT(fragment_num) == 1) { 1365 | /* We don't want to repeat ourselves in the info column if there are fragments */ 1366 | if (serv == TIBIA_LOGINSERV) 1367 | col_set_str(pinfo->cinfo, COL_INFO, "Login"); 1368 | else if (pinfo->srcport == convo->servport) 1369 | col_set_str(pinfo->cinfo, COL_INFO, "Server"); 1370 | else 1371 | col_set_str(pinfo->cinfo, COL_INFO, "Client"); 1372 | 1373 | } 1374 | 1375 | proto_item *ti = proto_tree_add_item(tree, proto_tibia, tvb, 0, -1, ENC_NA); 1376 | proto_tree *tibia_tree = proto_item_add_subtree(ti, ett_tibia); 1377 | 1378 | proto_tree_add_item(tibia_tree, hf_tibia_len, tvb, offset, 2, ENC_LITTLE_ENDIAN); 1379 | offset += 2; 1380 | if (convo->has.adler32) { 1381 | proto_tree_add_checksum(tibia_tree, tvb, offset, hf_tibia_adler32, hf_tibia_adler32_status, &ei_adler32_checksum_bad, pinfo, computed_cksum, ENC_LITTLE_ENDIAN, PROTO_CHECKSUM_VERIFY); 1382 | offset += 4; 1383 | } else if (convo->has.compression) { 1384 | offset += 4; 1385 | } 1386 | 1387 | if (serv == TIBIA_GAMESERV) 1388 | return dissect_game_packet(convo, tvb, offset, pinfo, tibia_tree, is_xtea_encrypted, GPOINTER_TO_UINT(fragment_num) == 1); 1389 | 1390 | proto_tree_add_item(tibia_tree, hf_tibia_client_command, tvb, offset, 1, ENC_LITTLE_ENDIAN); 1391 | offset += 1; 1392 | proto_tree_add_item(tibia_tree, hf_tibia_os, tvb, offset, 2, ENC_LITTLE_ENDIAN); 1393 | offset += 2; 1394 | 1395 | convo->proto_version = tvb_get_letohs(tvb, offset); 1396 | convo->has = get_version_traits(convo->proto_version); 1397 | proto_tree_add_item(tibia_tree, hf_tibia_proto_version, tvb, offset, 2, ENC_LITTLE_ENDIAN); 1398 | offset += 2; 1399 | if (convo->has.client_version) { 1400 | proto_tree_add_item(tibia_tree, hf_tibia_client_version, tvb, offset, 4, ENC_LITTLE_ENDIAN); 1401 | offset += 4; 1402 | } 1403 | if (convo->loginserv_is_peer) { 1404 | proto_tree *vertree; 1405 | /* The first 4 bytes of the client's tibia.pic, tibia.dat and tibia.spr files */ 1406 | proto_item *subti = proto_tree_add_item(tibia_tree, hf_tibia_file_versions, tvb, offset, 12, ENC_NA); 1407 | vertree = proto_item_add_subtree(subti, ett_file_versions); 1408 | proto_tree_add_item(vertree, hf_tibia_file_version_spr, tvb, offset, 4, ENC_BIG_ENDIAN); 1409 | offset += 4; 1410 | proto_tree_add_item(vertree, hf_tibia_file_version_dat, tvb, offset, 4, ENC_BIG_ENDIAN); 1411 | offset += 4; 1412 | proto_tree_add_item(vertree, hf_tibia_file_version_pic, tvb, offset, 4, ENC_BIG_ENDIAN); 1413 | offset += 4; 1414 | } else if (convo->has.game_content_revision) { 1415 | proto_tree_add_item(tibia_tree, hf_tibia_content_revision, tvb, offset, 4, ENC_LITTLE_ENDIAN); 1416 | offset += 2; 1417 | } 1418 | 1419 | if (convo->has.game_preview) { 1420 | proto_tree_add_item(tibia_tree, hf_tibia_game_preview_state, tvb, offset, 1, ENC_NA); 1421 | offset += 1; 1422 | } 1423 | 1424 | int rsa1_end = 0; /* End of first RSA block */ 1425 | if (convo->has.rsa) { 1426 | gcry_sexp_t privkey; 1427 | if (!(privkey = convo_get_privkey(convo))) { 1428 | proto_tree_add_item(tibia_tree, hf_tibia_undecoded_rsa_data, tvb, offset, plen - offset, ENC_NA); 1429 | return offset; 1430 | } 1431 | 1432 | guint ciphertext_len = tvb_captured_length_remaining(tvb, offset); 1433 | if (ciphertext_len < 128) { 1434 | expert_add_info(pinfo, ti, &ei_rsa_ciphertext_too_short); 1435 | return offset; 1436 | } 1437 | rsa1_end = offset + 128; 1438 | guint8 *payload = (guint8*)tvb_memdup(pinfo->pool, tvb, offset, 128); 1439 | 1440 | char *err = NULL; 1441 | size_t payload_len; 1442 | if (!(payload_len = rsa_decrypt_inplace(128, payload, privkey, FALSE, &err))) { 1443 | expert_add_info_format(pinfo, ti, &ei_rsa_decrypt_failed, "Decrypting RSA block failed: %s", err); 1444 | g_free(err); 1445 | return offset; 1446 | } 1447 | size_t leading_zeroes = 128 - payload_len; 1448 | memmove(payload + leading_zeroes, payload, payload_len); 1449 | memset(payload, 0x00, leading_zeroes); 1450 | 1451 | tvb_decrypted = tvb_new_child_real_data(tvb, payload, 128, 128); 1452 | add_new_data_source(pinfo, tvb_decrypted, "Decrypted Login Data"); 1453 | 1454 | if (tvb_get_guint8(tvb_decrypted, 0) != 0x00) { 1455 | expert_add_info(pinfo, ti, &ei_rsa_plaintext_no_leading_zero); 1456 | return offset; 1457 | } 1458 | 1459 | offset = 1; 1460 | 1461 | tvb_memcpy(tvb_decrypted, convo->xtea_key, 1, XTEA_KEY_LEN); 1462 | proto_tree_add_item(tibia_tree, hf_tibia_xtea_key, tvb_decrypted, 1, XTEA_KEY_LEN, ENC_NA); 1463 | offset += XTEA_KEY_LEN; 1464 | convo->xtea_framenum = pinfo->num; 1465 | } 1466 | 1467 | if (!convo->loginserv_is_peer && convo->has.gmbyte) { 1468 | proto_tree_add_item(tibia_tree, hf_tibia_loginflags_gm, tvb_decrypted, offset, 1, ENC_NA); 1469 | offset += 1; 1470 | } 1471 | 1472 | int len; 1473 | if (convo->has.session_key && !convo->loginserv_is_peer) { 1474 | /* OTServs I tested against use "$acc\n$pacc" as session key */ 1475 | if (convo->session_key) { 1476 | proto_tree_add_item_ret_length(tibia_tree, hf_tibia_session_key, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len); 1477 | } else { 1478 | proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_session_key, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->session_key, &len); 1479 | } 1480 | offset += len; 1481 | } else if (convo->has.acc_name) { 1482 | if (convo->acc) { 1483 | proto_tree_add_item_ret_length(tibia_tree, hf_tibia_acc_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len); 1484 | } else { 1485 | proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_acc_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->acc, &len); 1486 | } 1487 | offset += len; 1488 | } else /* account number */ { 1489 | char *accnum = wmem_strdup_printf(wmem_packet_scope(), "%" G_GUINT32_FORMAT, tvb_get_letohl(tvb_decrypted, offset)); 1490 | proto_tree_add_string(tibia_tree, hf_tibia_acc_number, tvb_decrypted, offset, 4, accnum); 1491 | if (!convo->acc) 1492 | convo->acc = (guint8*)wmem_strdup(wmem_file_scope(), accnum); 1493 | offset += 4; 1494 | } 1495 | 1496 | if (!convo->loginserv_is_peer) { 1497 | if (convo->char_name) { 1498 | proto_tree_add_item_ret_length(tibia_tree, hf_tibia_char_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len); 1499 | } else { 1500 | proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_char_name, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->char_name, &len); 1501 | } 1502 | offset += len; 1503 | } 1504 | 1505 | if (!convo->has.session_key || convo->loginserv_is_peer) { 1506 | if (convo->pass) { 1507 | proto_tree_add_item_ret_length(tibia_tree, hf_tibia_acc_pass, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, &len); 1508 | } else { 1509 | proto_tree_add_item_ret_string_and_length(tibia_tree, hf_tibia_acc_pass, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN | convo->has.string_enc, wmem_file_scope(), &convo->pass, &len); 1510 | } 1511 | offset += len; 1512 | } 1513 | 1514 | if (convo->loginserv_is_peer && convo->has.hwinfo) { 1515 | proto_item *item; 1516 | proto_tree *infotree, *subtree; 1517 | 1518 | item = proto_tree_add_item(tibia_tree, hf_tibia_client_info, tvb_decrypted, offset, 47, ENC_NA); 1519 | infotree = proto_item_add_subtree(item, ett_client_info); 1520 | 1521 | /* Subtree { */ 1522 | guint locale_id; 1523 | const guint8 *locale_name; 1524 | 1525 | item = proto_tree_add_item(infotree, hf_tibia_client_locale, tvb_decrypted, offset, 4, ENC_NA); 1526 | subtree = proto_item_add_subtree(item, ett_locale); 1527 | 1528 | proto_tree_add_item_ret_uint(subtree, hf_tibia_client_locale_id, tvb_decrypted, offset, 1, ENC_NA, &locale_id); 1529 | offset += 1; 1530 | 1531 | proto_tree_add_item_ret_string(subtree, hf_tibia_client_locale_name, tvb_decrypted, offset, 3, convo->has.string_enc|ENC_NA, wmem_packet_scope(), &locale_name); 1532 | offset += 3; 1533 | proto_item_set_text(item, "Locale: %s (0x%X)", locale_name, locale_id); 1534 | /* } */ 1535 | 1536 | proto_tree_add_item(infotree, hf_tibia_client_ram, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN); 1537 | offset += 2; 1538 | 1539 | proto_tree_add_item(infotree, hf_tibia_unknown, tvb_decrypted, offset, 6, ENC_NA); 1540 | offset += 6; 1541 | 1542 | /* Subtree { */ 1543 | guint clock1, clock2; 1544 | const guint8 *cpu; 1545 | 1546 | item = proto_tree_add_item(infotree, hf_tibia_client_cpu, tvb_decrypted, offset, 15, ENC_NA); 1547 | subtree = proto_item_add_subtree(item, ett_cpu); 1548 | 1549 | proto_tree_add_item_ret_string(subtree, hf_tibia_client_cpu_name, tvb_decrypted, offset, 9, convo->has.string_enc|ENC_NA, wmem_packet_scope(), &cpu); 1550 | offset += 9; 1551 | 1552 | proto_tree_add_item(subtree, hf_tibia_unknown, tvb_decrypted, offset, 2, ENC_NA); 1553 | offset += 2; 1554 | 1555 | proto_tree_add_item_ret_uint(subtree, hf_tibia_client_clock, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &clock1); 1556 | offset += 2; 1557 | 1558 | proto_tree_add_item_ret_uint(subtree, hf_tibia_client_clock2, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &clock2); 1559 | offset += 2; 1560 | 1561 | proto_item_set_text(item, "CPU: %s (%uMhz/%uMhz)", cpu, clock2, clock1); 1562 | /* } */ 1563 | 1564 | 1565 | proto_tree_add_item(infotree, hf_tibia_unknown, tvb_decrypted, offset, 4, ENC_NA); 1566 | offset += 4; 1567 | 1568 | proto_tree_add_item(infotree, hf_tibia_client_gpu, tvb_decrypted, offset, 9, convo->has.string_enc|ENC_NA); 1569 | offset += 9; 1570 | 1571 | proto_tree_add_item(infotree, hf_tibia_client_vram, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN); 1572 | offset += 2; 1573 | 1574 | /* Subtree { */ 1575 | guint x, y, hz; 1576 | 1577 | item = proto_tree_add_item(infotree, hf_tibia_client_resolution, tvb_decrypted, offset, 5, ENC_NA); 1578 | subtree = proto_item_add_subtree(item, ett_resolution); 1579 | 1580 | proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_x, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &x); 1581 | offset += 2; 1582 | proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_y, tvb_decrypted, offset, 2, ENC_LITTLE_ENDIAN, &y); 1583 | offset += 2; 1584 | proto_tree_add_item_ret_uint(subtree, hf_tibia_client_resolution_hz, tvb_decrypted, offset, 1, ENC_LITTLE_ENDIAN, &hz); 1585 | offset += 1; 1586 | 1587 | proto_item_set_text(item, "Resolution: %ux%u @ %uHz", x, y, hz); 1588 | /* } */ 1589 | 1590 | } else if (!convo->loginserv_is_peer && convo->has.nonce) { 1591 | proto_tree_add_item(tibia_tree, hf_tibia_nonce, tvb_decrypted, offset, 5, ENC_NA); 1592 | offset += 5; 1593 | } 1594 | 1595 | if (convo->has.rsa) { 1596 | /* Undecoded hardware info maybe */ 1597 | call_data_dissector(tvb_new_subset_length(tvb_decrypted, offset, 128 - offset), pinfo, tibia_tree); 1598 | } 1599 | 1600 | if (rsa1_end) 1601 | offset = rsa1_end; 1602 | 1603 | if (offset != plen) { 1604 | /* TODO Extended GPU info and authentication token (RSA-encrypted again) */ 1605 | call_data_dissector(tvb_new_subset_length(tvb, offset, plen - offset), pinfo, tibia_tree); 1606 | } 1607 | return plen; 1608 | } 1609 | 1610 | static const value_string operating_systems[] = { 1611 | { 2, "Windows" }, 1612 | { 0, NULL } 1613 | }; 1614 | 1615 | static const value_string speech_types[] = { 1616 | { 0x1, "Say" }, 1617 | { 0x2, "Whisper" }, 1618 | { 0x3, "Yell" }, 1619 | { 0x7, "Public Channel" }, 1620 | { 0, NULL } 1621 | }; 1622 | 1623 | static guint 1624 | rsakey_hash(gconstpointer _rsakey) 1625 | { 1626 | const struct rsakey *rsakey = (const struct rsakey *)_rsakey; 1627 | return add_address_to_hash(rsakey->port, &rsakey->addr); 1628 | } 1629 | 1630 | static gboolean 1631 | rsakey_equal(gconstpointer _a, gconstpointer _b) 1632 | { 1633 | const struct rsakey *a = (const struct rsakey *)_a, 1634 | *b = (const struct rsakey *)_b; 1635 | return a->port == b->port && addresses_equal(&a->addr, &b->addr); 1636 | } 1637 | static void 1638 | rsakey_free(void *_rsakey) 1639 | { 1640 | struct rsakey *rsakey = (struct rsakey *)_rsakey; 1641 | 1642 | /* gcry_sexp_release(rsakey->privkey); */ /* private key may be shared. */ 1643 | free_address_wmem(NULL, &rsakey->addr); 1644 | g_free(rsakey); 1645 | } 1646 | 1647 | #if defined(HAVE_LIBGNUTLS) 1648 | static void 1649 | rsa_parse_uat(void) 1650 | { 1651 | g_hash_table_remove_all(rsakeys); 1652 | 1653 | for (guint i = 0; i < nrsakeys; i++) { 1654 | struct rsakeys_assoc *uats = &rsakeylist_uats[i]; 1655 | 1656 | /* try to load keys file first */ 1657 | FILE *fp = ws_fopen(uats->keyfile, "rb"); 1658 | if (!fp) { 1659 | report_open_failure(uats->keyfile, errno, FALSE); 1660 | return; 1661 | } 1662 | 1663 | gnutls_x509_privkey_t priv_key; 1664 | char *err = NULL; 1665 | if (*uats->password) { 1666 | priv_key = rsa_load_pkcs12(fp, uats->password, &err); 1667 | if (err) { 1668 | report_failure("%s\n", err); 1669 | g_free(err); 1670 | } 1671 | } else { 1672 | priv_key = rsa_load_pem_key(fp, &err); 1673 | if (err) { 1674 | report_failure("%s\n", err); 1675 | g_free(err); 1676 | } 1677 | } 1678 | fclose(fp); 1679 | 1680 | if (!priv_key) { 1681 | report_failure("Can't load private key from %s\n", uats->keyfile); 1682 | return; 1683 | } 1684 | 1685 | struct rsakey *entry; 1686 | guint32 ipaddr; 1687 | gcry_sexp_t private_key = rsa_privkey_to_sexp(priv_key, &err); 1688 | if (!private_key) { 1689 | g_free(err); 1690 | report_failure("Can't extract private key parameters for %s", uats->keyfile); 1691 | goto end; 1692 | } 1693 | 1694 | entry = g_new(struct rsakey, 1); 1695 | ws_strtou16(uats->port, NULL, &entry->port); 1696 | ipaddr = ipv4tonl(uats->ipaddr); 1697 | alloc_address_wmem(NULL, &entry->addr, AT_IPv4, sizeof ipaddr, &ipaddr); 1698 | entry->privkey = private_key; 1699 | 1700 | 1701 | g_hash_table_insert(rsakeys, entry, entry->privkey); 1702 | 1703 | end: 1704 | gnutls_x509_privkey_deinit(priv_key); 1705 | } 1706 | } 1707 | #else 1708 | static void 1709 | rsa_parse_uat(void) 1710 | { 1711 | report_failure("Can't load private key files, GnuTLS support is not compiled in."); 1712 | } 1713 | #endif 1714 | 1715 | static void 1716 | rsakeys_free_cb(void *r) 1717 | { 1718 | struct rsakeys_assoc *h = (struct rsakeys_assoc *)r; 1719 | 1720 | g_free(h->ipaddr); 1721 | g_free(h->port); 1722 | g_free(h->keyfile); 1723 | g_free(h->password); 1724 | } 1725 | 1726 | static void* 1727 | rsakeys_copy_cb(void *dst_, const void *src_, size_t len _U_) 1728 | { 1729 | const struct rsakeys_assoc *src = (const struct rsakeys_assoc *)src_; 1730 | struct rsakeys_assoc *dst = (struct rsakeys_assoc *)dst_; 1731 | 1732 | dst->ipaddr = g_strdup(src->ipaddr); 1733 | dst->port = g_strdup(src->port); 1734 | dst->keyfile = g_strdup(src->keyfile); 1735 | dst->password = g_strdup(src->password); 1736 | 1737 | return dst; 1738 | } 1739 | 1740 | static gboolean 1741 | rsakeys_uat_fld_ip_chk_cb(void* r _U_, const char* ipaddr, guint len _U_, const void* u1 _U_, const void* u2 _U_, char** err) 1742 | { 1743 | /* There are no Tibia IPv6 servers, although Tibia 11.0+'s Protocol in theory supports it */ 1744 | if (ipaddr && g_hostname_is_ip_address(ipaddr) && strchr(ipaddr, '.')) { 1745 | *err = NULL; 1746 | return TRUE; 1747 | } 1748 | 1749 | *err = g_strdup_printf("No IPv4 address given."); 1750 | return FALSE; 1751 | } 1752 | 1753 | static gboolean 1754 | rsakeys_uat_fld_port_chk_cb(void *_record _U_, const char *str, guint len _U_, const void *chk_data _U_, const void *fld_data _U_, char **err) 1755 | { 1756 | guint16 val; 1757 | if (!ws_strtou16(str, NULL, &val)) { 1758 | *err = g_strdup("Invalid argument. Expected a decimal between [0-65535]"); 1759 | return FALSE; 1760 | } 1761 | *err = NULL; 1762 | return TRUE; 1763 | } 1764 | 1765 | static gboolean 1766 | rsakeys_uat_fld_fileopen_chk_cb(void* r _U_, const char* p, guint len _U_, const void* u1 _U_, const void* u2 _U_, char** err) 1767 | { 1768 | if (p && *p) { 1769 | ws_statb64 st; 1770 | if (ws_stat64(p, &st) != 0) { 1771 | *err = g_strdup_printf("File '%s' does not exist or access is denied.", p); 1772 | return FALSE; 1773 | } 1774 | } else { 1775 | *err = g_strdup("No filename given."); 1776 | return FALSE; 1777 | } 1778 | 1779 | *err = NULL; 1780 | return TRUE; 1781 | } 1782 | 1783 | #ifdef HAVE_LIBGNUTLS 1784 | static gboolean 1785 | rsakeys_uat_fld_password_chk_cb(void *r, const char *p, guint len _U_, const void *u1 _U_, const void *u2 _U_, char **err) 1786 | { 1787 | if (p && *p) { 1788 | struct rsakeys_assoc *f = (struct rsakeys_assoc *)r; 1789 | FILE *fp = ws_fopen(f->keyfile, "rb"); 1790 | if (fp) { 1791 | char *msg = NULL; 1792 | gnutls_x509_privkey_t priv_key = rsa_load_pkcs12(fp, p, &msg); 1793 | if (!priv_key) { 1794 | fclose(fp); 1795 | *err = g_strdup_printf("Could not load PKCS#12 key file: %s", msg); 1796 | g_free(msg); 1797 | return FALSE; 1798 | } 1799 | g_free(msg); 1800 | gnutls_x509_privkey_deinit(priv_key); 1801 | fclose(fp); 1802 | } else { 1803 | *err = g_strdup_printf("Leave this field blank if the keyfile is not PKCS#12."); 1804 | return FALSE; 1805 | } 1806 | } 1807 | 1808 | *err = NULL; 1809 | return TRUE; 1810 | } 1811 | #else 1812 | static gboolean 1813 | rsakeys_uat_fld_password_chk_cb(void *r _U_, const char *p _U_, guint len _U_, const void *u1 _U_, const void *u2 _U_, char **err) 1814 | { 1815 | *err = g_strdup("Cannot load key files, support is not compiled in."); 1816 | return FALSE; 1817 | } 1818 | #endif 1819 | 1820 | static void 1821 | xtea_parse_uat(void) 1822 | { 1823 | g_hash_table_remove_all(xteakeys); 1824 | 1825 | for (guint i = 0; i < nxteakeys; i++) { 1826 | guint key_idx = 0; 1827 | guint8 *key = (guint8*)g_malloc(XTEA_KEY_LEN); 1828 | 1829 | for (const char *str = xteakeylist_uats[i].key; str[0] && str[1] && key_idx < XTEA_KEY_LEN; str++) { 1830 | if (g_ascii_ispunct(*str)) 1831 | continue; 1832 | 1833 | key[key_idx++] = (g_ascii_xdigit_value(str[0]) << 4) 1834 | + g_ascii_xdigit_value(str[1]); 1835 | str++; 1836 | } 1837 | 1838 | g_hash_table_insert(xteakeys, GUINT_TO_POINTER(xteakeylist_uats[i].framenum), key); 1839 | } 1840 | } 1841 | 1842 | static void 1843 | xteakeys_free_cb(void *r) 1844 | { 1845 | struct xteakeys_assoc *h = (struct xteakeys_assoc *)r; 1846 | 1847 | g_free(h->key); 1848 | } 1849 | 1850 | static void* 1851 | xteakeys_copy_cb(void *dst_, const void *src_, size_t len _U_) 1852 | { 1853 | const struct xteakeys_assoc *src = (const struct xteakeys_assoc *)src_; 1854 | struct xteakeys_assoc *dst = (struct xteakeys_assoc *)dst_; 1855 | 1856 | dst->framenum = src->framenum; 1857 | dst->key = g_strdup(src->key); 1858 | 1859 | return dst; 1860 | } 1861 | 1862 | static gboolean 1863 | xteakeys_uat_fld_key_chk_cb(void *r _U_, const char *key, guint len, const void *u1 _U_, const void *u2 _U_, char **err) 1864 | { 1865 | if (len >= XTEA_KEY_LEN*2) { 1866 | gsize i = 0; 1867 | 1868 | do { 1869 | if (g_ascii_ispunct(*key)) 1870 | continue; 1871 | if (!g_ascii_isxdigit(*key)) 1872 | break; 1873 | i++; 1874 | } while (*++key); 1875 | 1876 | if (*key == '\0' && i == 2*XTEA_KEY_LEN) { 1877 | *err = NULL; 1878 | return TRUE; 1879 | } 1880 | } 1881 | 1882 | *err = g_strdup_printf("XTEA keys are 32 character long hex strings."); 1883 | return FALSE; 1884 | } 1885 | 1886 | 1887 | void 1888 | proto_register_tibia(void) 1889 | { 1890 | static hf_register_info hf[] = { 1891 | { &hf_tibia_len, 1892 | { "Packet length", "tibia.len", 1893 | FT_UINT16, BASE_DEC, 1894 | NULL, 0x0, 1895 | NULL, HFILL } 1896 | }, 1897 | { &hf_tibia_adler32, 1898 | { "Adler32 checksum", "tibia.checksum", 1899 | FT_UINT32, BASE_HEX, 1900 | NULL, 0x0, 1901 | NULL, HFILL } 1902 | }, 1903 | { &hf_tibia_adler32_status, 1904 | { "Checksum status", "tibia.checksum.status", 1905 | FT_UINT8, BASE_NONE, 1906 | VALS(proto_checksum_vals), 0x0, 1907 | NULL, HFILL } 1908 | }, 1909 | { &hf_tibia_nonce, 1910 | { "Game server nonce", "tibia.nonce", 1911 | FT_BYTES, BASE_NONE, 1912 | NULL, 0x0, 1913 | NULL, HFILL } 1914 | }, 1915 | { &hf_tibia_os, 1916 | { "Operating system", "tibia.os", 1917 | FT_UINT16, BASE_HEX, 1918 | VALS(operating_systems), 0x0, 1919 | NULL, HFILL } 1920 | }, 1921 | { &hf_tibia_proto_version, 1922 | { "Protocol version", "tibia.version", 1923 | FT_UINT16, BASE_DEC, 1924 | NULL, 0x0, 1925 | NULL, HFILL } 1926 | }, 1927 | { &hf_tibia_client_version, 1928 | { "Client version", "tibia.client_version", 1929 | FT_UINT32, BASE_DEC, 1930 | NULL, 0x0, 1931 | NULL, HFILL } 1932 | }, 1933 | { &hf_tibia_file_versions, 1934 | { "File versions", "tibia.version.files", 1935 | FT_NONE, BASE_NONE, NULL, 0x0, 1936 | NULL, HFILL } 1937 | }, 1938 | { &hf_tibia_file_version_spr, 1939 | { "Tibia.spr version", "tibia.version.spr", 1940 | FT_UINT32, BASE_HEX, 1941 | NULL, 0x0, 1942 | NULL, HFILL } 1943 | }, 1944 | { &hf_tibia_file_version_dat, 1945 | { "Tibia.dat version", "tibia.version.dat", 1946 | FT_UINT32, BASE_HEX, 1947 | NULL, 0x0, 1948 | NULL, HFILL } 1949 | }, 1950 | { &hf_tibia_file_version_pic, 1951 | { "Tibia.pic version", "tibia.version.pic", 1952 | FT_UINT32, BASE_HEX, 1953 | NULL, 0x0, 1954 | NULL, HFILL } 1955 | }, 1956 | { &hf_tibia_content_revision, 1957 | { "Content revision", "tibia.version.content", 1958 | FT_UINT16, BASE_HEX, 1959 | NULL, 0x0, 1960 | NULL, HFILL } 1961 | }, 1962 | { &hf_tibia_undecoded_rsa_data, 1963 | { "RSA-encrypted login data", "tibia.rsa_data", 1964 | FT_BYTES, BASE_NONE, 1965 | NULL, 0x0, 1966 | NULL, HFILL } 1967 | }, 1968 | { &hf_tibia_undecoded_xtea_data, 1969 | { "XTEA-encrypted game data", "tibia.xtea_data", 1970 | FT_BYTES, BASE_NONE, 1971 | NULL, 0x0, 1972 | NULL, HFILL } 1973 | }, 1974 | { &hf_tibia_unknown, 1975 | { "Unknown Data", "tibia.unknown", 1976 | FT_BYTES, BASE_NONE, 1977 | NULL, 0x0, 1978 | NULL, HFILL } 1979 | }, 1980 | { &hf_tibia_xtea_key, 1981 | { "Symmetric key (XTEA)", "tibia.xtea", 1982 | FT_BYTES, BASE_NONE, 1983 | NULL, 0x0, 1984 | NULL, HFILL } 1985 | }, 1986 | { &hf_tibia_loginflags_gm, 1987 | { "Gamemaster", "tibia.login.flags.gm", 1988 | FT_BOOLEAN, 8, 1989 | NULL, 0x1, 1990 | NULL, HFILL } 1991 | }, 1992 | { &hf_tibia_game_preview_state, 1993 | { "Game Preview State", "tibia.login.flags.preview", 1994 | FT_BOOLEAN, 8, 1995 | NULL, 0x1, 1996 | NULL, HFILL } 1997 | }, 1998 | { &hf_tibia_char_cond, 1999 | {"Character Condition", "tibia.cond", 2000 | FT_UINT32, BASE_HEX, 2001 | NULL, 0, 2002 | NULL, HFILL} 2003 | }, 2004 | { &hf_tibia_char_cond_poisoned, 2005 | { "Poisoned", "tibia.cond.poisoned", 2006 | FT_BOOLEAN, 32, 2007 | TFS(&tfs_yes_no), COND_POISONED, 2008 | NULL, HFILL } 2009 | }, 2010 | { &hf_tibia_char_cond_burning, 2011 | { "Burning", "tibia.cond.burning", 2012 | FT_BOOLEAN, 32, 2013 | TFS(&tfs_yes_no), COND_BURNING, 2014 | NULL, HFILL } 2015 | }, 2016 | { &hf_tibia_char_cond_electrocuted, 2017 | { "Electrocuted", "tibia.cond.electrocuted", 2018 | FT_BOOLEAN, 32, 2019 | TFS(&tfs_yes_no), COND_ELECTROCUTED, 2020 | NULL, HFILL } 2021 | }, 2022 | { &hf_tibia_char_cond_drunk, 2023 | { "Drunk", "tibia.cond.drunk", 2024 | FT_BOOLEAN, 32, 2025 | TFS(&tfs_yes_no), COND_DRUNK, 2026 | NULL, HFILL } 2027 | }, 2028 | { &hf_tibia_char_cond_manashield, /* Utamo Vita */ 2029 | { "Mana Shield", "tibia.cond.manashield", 2030 | FT_BOOLEAN, 32, 2031 | TFS(&tfs_yes_no), COND_MANASHIELD, 2032 | NULL, HFILL } 2033 | }, 2034 | { &hf_tibia_char_cond_paralyzed, 2035 | { "Paralyzed", "tibia.cond.paralyzed", 2036 | FT_BOOLEAN, 32, 2037 | TFS(&tfs_yes_no), COND_PARALYZED, 2038 | NULL, HFILL } 2039 | }, 2040 | { &hf_tibia_char_cond_haste, 2041 | { "Haste", "tibia.cond.haste", 2042 | FT_BOOLEAN, 32, 2043 | TFS(&tfs_yes_no), COND_HASTE, 2044 | NULL, HFILL } 2045 | }, 2046 | { &hf_tibia_char_cond_battle, 2047 | { "Battle lock", "tibia.cond.battle", 2048 | FT_BOOLEAN, 32, 2049 | TFS(&tfs_yes_no), COND_BATTLE, 2050 | NULL, HFILL } 2051 | }, 2052 | { &hf_tibia_char_cond_drowning, 2053 | { "Drowning", "tibia.cond.drowning", 2054 | FT_BOOLEAN, 32, 2055 | TFS(&tfs_yes_no), COND_DROWNING, 2056 | NULL, HFILL } 2057 | }, 2058 | { &hf_tibia_char_cond_freezing, 2059 | { "Freezing", "tibia.cond.freezing", 2060 | FT_BOOLEAN, 32, 2061 | TFS(&tfs_yes_no), COND_FREEZING, 2062 | NULL, HFILL } 2063 | }, 2064 | { &hf_tibia_char_cond_dazzled, 2065 | { "Dazzled", "tibia.cond.dazzled", 2066 | FT_BOOLEAN, 32, 2067 | TFS(&tfs_yes_no), COND_DAZZLED, 2068 | NULL, HFILL } 2069 | }, 2070 | { &hf_tibia_char_cond_cursed, 2071 | { "Cursed", "tibia.cond.cursed", 2072 | FT_BOOLEAN, 32, 2073 | TFS(&tfs_yes_no), COND_CURSED, 2074 | NULL, HFILL } 2075 | }, 2076 | { &hf_tibia_char_cond_buff, /* e.g. after casting Utura */ 2077 | { "Buff", "tibia.cond.buff", 2078 | FT_BOOLEAN, 32, 2079 | TFS(&tfs_yes_no), COND_BUFF, 2080 | NULL, HFILL } 2081 | }, 2082 | { &hf_tibia_char_cond_pzblock, /* Blocked from entering PZ */ 2083 | { "Protection Zone Block", "tibia.cond.pzblock", 2084 | FT_BOOLEAN, 32, 2085 | TFS(&tfs_yes_no), COND_PZBLOCK, 2086 | NULL, HFILL } 2087 | }, 2088 | { &hf_tibia_char_cond_pz, 2089 | { "Protection Zone", "tibia.cond.pz", 2090 | FT_BOOLEAN, 32, 2091 | TFS(&tfs_yes_no), COND_PZ, 2092 | NULL, HFILL } 2093 | }, 2094 | { &hf_tibia_char_cond_bleeding, 2095 | { "Bleeding", "tibia.cond.bleeding", 2096 | FT_BOOLEAN, 32, 2097 | TFS(&tfs_yes_no), COND_BLEEDING, 2098 | NULL, HFILL } 2099 | }, 2100 | { &hf_tibia_char_cond_hungry, 2101 | { "Hungry", "tibia.cond.hungry", 2102 | FT_BOOLEAN, 32, 2103 | TFS(&tfs_yes_no), COND_HUNGRY, 2104 | NULL, HFILL } 2105 | }, 2106 | { &hf_tibia_acc_name, 2107 | { "Account", "tibia.acc", 2108 | FT_UINT_STRING, BASE_NONE, 2109 | NULL, 0x0, 2110 | NULL, HFILL } 2111 | }, 2112 | { &hf_tibia_acc_number, 2113 | { "Account", "tibia.acc", 2114 | FT_STRING, BASE_NONE, 2115 | NULL, 0x0, 2116 | NULL, HFILL } 2117 | }, 2118 | { &hf_tibia_session_key, 2119 | { "Session key", "tibia.session_key", 2120 | FT_UINT_STRING, BASE_NONE, 2121 | NULL, 0x0, 2122 | NULL, HFILL } 2123 | }, 2124 | { &hf_tibia_char_name, 2125 | { "Character name", "tibia.char", 2126 | FT_UINT_STRING, BASE_NONE, 2127 | NULL, 0x0, 2128 | NULL, HFILL } 2129 | }, 2130 | { &hf_tibia_acc_pass, 2131 | { "Password", "tibia.pass", 2132 | FT_UINT_STRING, BASE_NONE, 2133 | NULL, 0x0, 2134 | NULL, HFILL } 2135 | }, 2136 | { &hf_tibia_char_name_convo, 2137 | { "Character name", "tibia.char", 2138 | FT_STRING, BASE_NONE, 2139 | NULL, 0x0, 2140 | NULL, HFILL } 2141 | }, 2142 | { &hf_tibia_acc_name_convo, 2143 | { "Account", "tibia.acc", 2144 | FT_STRING, BASE_NONE, 2145 | NULL, 0x0, 2146 | NULL, HFILL } 2147 | }, 2148 | { &hf_tibia_acc_pass_convo, 2149 | { "Password", "tibia.pass", 2150 | FT_STRING, BASE_NONE, 2151 | NULL, 0x0, 2152 | NULL, HFILL } 2153 | }, 2154 | { &hf_tibia_session_key_convo, 2155 | { "Session key", "tibia.session_key", 2156 | FT_STRING, BASE_NONE, 2157 | NULL, 0x0, 2158 | NULL, HFILL } 2159 | }, 2160 | { &hf_tibia_client_info, 2161 | { "Client information", "tibia.client.info", 2162 | FT_NONE, BASE_NONE, 2163 | NULL, 0x0, 2164 | NULL, HFILL } 2165 | }, 2166 | { &hf_tibia_client_locale, 2167 | { "Locale", "tibia.client.locale", 2168 | FT_NONE, BASE_NONE, 2169 | NULL, 0x0, 2170 | NULL, HFILL } 2171 | }, 2172 | { &hf_tibia_client_locale_id, 2173 | { "Locale ID", "tibia.client.locale.id", 2174 | FT_UINT8, BASE_DEC, 2175 | NULL, 0x0, 2176 | NULL, HFILL } 2177 | }, 2178 | { &hf_tibia_client_locale_name, 2179 | { "Locale", "tibia.client.locale.name", 2180 | FT_STRING, BASE_NONE, 2181 | NULL, 0x0, 2182 | NULL, HFILL } 2183 | }, 2184 | { &hf_tibia_client_ram, 2185 | { "Total RAM", "tibia.client.ram", 2186 | FT_UINT8, BASE_DEC, 2187 | NULL, 0x0, 2188 | NULL, HFILL } 2189 | }, 2190 | { &hf_tibia_client_cpu, 2191 | { "CPU", "tibia.client.cpu", 2192 | FT_NONE, BASE_NONE, 2193 | NULL, 0x0, 2194 | NULL, HFILL } 2195 | }, 2196 | { &hf_tibia_client_cpu_name, 2197 | { "CPU", "tibia.client.cpu.name", 2198 | FT_STRINGZ, BASE_NONE, 2199 | NULL, 0x0, 2200 | NULL, HFILL } 2201 | }, 2202 | { &hf_tibia_client_clock, 2203 | { "CPU clock", "tibia.client.cpu.clock", 2204 | FT_UINT8, BASE_DEC, 2205 | NULL, 0x0, 2206 | NULL, HFILL } 2207 | }, 2208 | { &hf_tibia_client_clock2, 2209 | { "CPU clock2", "tibia.client.cpu.clock2", 2210 | FT_UINT8, BASE_DEC, 2211 | NULL, 0x0, 2212 | NULL, HFILL } 2213 | }, 2214 | { &hf_tibia_client_gpu, 2215 | { "GPU", "tibia.client.gpu", 2216 | FT_STRINGZ, BASE_NONE, 2217 | NULL, 0x0, 2218 | NULL, HFILL } 2219 | }, 2220 | { &hf_tibia_client_vram, 2221 | { "Video RAM", "tibia.client.vram", 2222 | FT_UINT8, BASE_DEC|BASE_UNIT_STRING, 2223 | &mb_unit, 0x0, 2224 | NULL, HFILL } 2225 | }, 2226 | { &hf_tibia_client_resolution, 2227 | { "Screen resolution", "tibia.client.resolution", 2228 | FT_NONE, BASE_NONE, 2229 | NULL, 0x0, 2230 | NULL, HFILL } 2231 | }, 2232 | { &hf_tibia_client_resolution_x, 2233 | { "Horizontal resolution", "tibia.client.resolution.x", 2234 | FT_UINT16, BASE_DEC, 2235 | NULL, 0x0, 2236 | NULL, HFILL } 2237 | }, 2238 | { &hf_tibia_client_resolution_y, 2239 | { "Vertical resolution", "tibia.client.resolution.y", 2240 | FT_UINT16, BASE_DEC, 2241 | NULL, 0x0, 2242 | NULL, HFILL } 2243 | }, 2244 | { &hf_tibia_client_resolution_hz, 2245 | { "Refresh rate", "tibia.client.resolution.hz", 2246 | FT_UINT8, BASE_DEC, 2247 | NULL, 0x0, 2248 | NULL, HFILL } 2249 | }, 2250 | { &hf_tibia_payload_len, 2251 | { "Payload length", "tibia.payload.len", 2252 | FT_UINT16, BASE_DEC, 2253 | NULL, 0x0, 2254 | NULL, HFILL } 2255 | }, 2256 | { &hf_tibia_loginserv_command, 2257 | { "Command", "tibia.cmd", 2258 | FT_UINT8, BASE_HEX, 2259 | VALS(from_loginserv_packet_types), 0x0, 2260 | NULL, HFILL } 2261 | }, 2262 | { &hf_tibia_gameserv_command, 2263 | { "Command", "tibia.cmd", 2264 | FT_UINT8, BASE_HEX|BASE_EXT_STRING, 2265 | &from_gameserv_packet_types_ext, 0x0, 2266 | NULL, HFILL } 2267 | }, 2268 | { &hf_tibia_client_command, 2269 | { "Command", "tibia.cmd", 2270 | FT_UINT8, BASE_HEX|BASE_EXT_STRING, 2271 | &from_client_packet_types_ext, 0x0, 2272 | NULL, HFILL } 2273 | }, 2274 | { &hf_tibia_motd, 2275 | { "Message of the day", "tibia.motd", 2276 | FT_UINT_STRING, BASE_NONE, NULL, 0x0, 2277 | NULL, HFILL } 2278 | }, 2279 | { &hf_tibia_dlg_error, 2280 | { "Error message", "tibia.login.err", 2281 | FT_UINT_STRING, BASE_NONE, NULL, 0x0, 2282 | NULL, HFILL } 2283 | }, 2284 | { &hf_tibia_dlg_info, 2285 | { "Info message", "tibia.login.info", 2286 | FT_UINT_STRING, BASE_NONE, NULL, 0x0, 2287 | NULL, HFILL } 2288 | }, 2289 | { &hf_tibia_charlist, 2290 | { "Character list", "tibia.charlist", 2291 | FT_NONE, BASE_NONE, NULL, 0x0, 2292 | NULL, HFILL } 2293 | }, 2294 | { &hf_tibia_charlist_length, 2295 | { "Character count", "tibia.charlist.count", 2296 | FT_UINT8, BASE_DEC, 2297 | NULL, 0x0, 2298 | NULL, HFILL } 2299 | }, 2300 | { &hf_tibia_charlist_entry_name, 2301 | { "Character name", "tibia.charlist.name", 2302 | FT_UINT_STRING, BASE_NONE, 2303 | NULL, 0x0, 2304 | NULL, HFILL } 2305 | }, 2306 | { &hf_tibia_charlist_entry_world, 2307 | { "World", "tibia.charlist.world", 2308 | FT_UINT_STRING, BASE_NONE, 2309 | NULL, 0x0, 2310 | NULL, HFILL } 2311 | }, 2312 | { &hf_tibia_charlist_entry_ip, 2313 | { "IP", "tibia.charlist.ip", 2314 | FT_IPv4, BASE_NONE, 2315 | NULL, 0x0, 2316 | NULL, HFILL } 2317 | }, 2318 | { &hf_tibia_charlist_entry_port, 2319 | { "Port", "tibia.charlist.port", 2320 | FT_UINT16, BASE_DEC, 2321 | NULL, 0x0, 2322 | NULL, HFILL } 2323 | }, 2324 | { &hf_tibia_worldlist, 2325 | { "World list", "tibia.worldlist", 2326 | FT_NONE, BASE_NONE, NULL, 0x0, 2327 | NULL, HFILL } 2328 | }, 2329 | { &hf_tibia_worldlist_entry_name, 2330 | { "World", "tibia.worldlist.name", 2331 | FT_UINT_STRING, BASE_NONE, 2332 | NULL, 0x0, 2333 | NULL, HFILL } 2334 | }, 2335 | { &hf_tibia_worldlist_length, 2336 | { "World count", "tibia.worldlist.count", 2337 | FT_UINT16, BASE_DEC, 2338 | NULL, 0x0, 2339 | NULL, HFILL } 2340 | }, 2341 | { &hf_tibia_worldlist_entry_id, 2342 | { "World ID", "tibia.worldlist.id", 2343 | FT_UINT8, BASE_DEC, 2344 | NULL, 0x0, 2345 | NULL, HFILL } 2346 | }, 2347 | { &hf_tibia_worldlist_entry_ip, 2348 | { "IP", "tibia.worldlist.ip", 2349 | FT_UINT_STRING, BASE_NONE, 2350 | NULL, 0x0, 2351 | NULL, HFILL } 2352 | }, 2353 | { &hf_tibia_worldlist_entry_port, 2354 | { "Port", "tibia.worldlist.port", 2355 | FT_UINT16, BASE_DEC, 2356 | NULL, 0x0, 2357 | NULL, HFILL } 2358 | }, 2359 | { &hf_tibia_worldlist_entry_preview, 2360 | { "Preview State", "tibia.worldlist.preview", 2361 | FT_BOOLEAN, 8, 2362 | NULL, 0x1, 2363 | NULL, HFILL } 2364 | }, 2365 | { &hf_tibia_pacc_days, 2366 | { "Premium days left", "tibia.pacc", 2367 | FT_UINT16, BASE_DEC, 2368 | NULL, 0x0, 2369 | NULL, HFILL } 2370 | }, 2371 | { &hf_tibia_channel_id, 2372 | { "Channel id", "tibia.channel.id", 2373 | FT_UINT16, BASE_HEX, 2374 | NULL, 0x0, 2375 | NULL, HFILL } 2376 | }, 2377 | { &hf_tibia_channel_name, 2378 | { "Channel name", "tibia.channel", 2379 | FT_UINT_STRING, BASE_NONE, 2380 | NULL, 0x0, 2381 | NULL, HFILL } 2382 | }, 2383 | { &hf_tibia_speech_type, 2384 | { "Type", "tibia.speechtype", 2385 | FT_UINT8, BASE_HEX, 2386 | VALS(speech_types), 0x0, 2387 | NULL, HFILL } 2388 | }, 2389 | { &hf_tibia_chat_msg, 2390 | { "Message", "tibia.msg", 2391 | FT_UINT_STRING, BASE_NONE, NULL, 0x0, 2392 | NULL, HFILL } 2393 | }, 2394 | { &hf_tibia_coords_x, 2395 | { "X-Coordinate", "tibia.coord.x", 2396 | FT_UINT16, BASE_DEC, NULL, 0x0, 2397 | NULL, HFILL } 2398 | }, 2399 | { &hf_tibia_coords_y, 2400 | { "Y-Coordinate", "tibia.coords.y", 2401 | FT_UINT16, BASE_DEC, NULL, 0x0, 2402 | NULL, HFILL } 2403 | }, 2404 | { &hf_tibia_coords_z, 2405 | { "Z-Coordinate", "tibia.coords.z", 2406 | FT_UINT8, BASE_DEC, NULL, 0x0, 2407 | NULL, HFILL } 2408 | }, 2409 | { &hf_tibia_coords, 2410 | { "Coordinates", "tibia.coords", 2411 | FT_STRING, BASE_NONE, 2412 | NULL, 0x0, 2413 | NULL, HFILL } 2414 | }, 2415 | { &hf_tibia_stackpos, 2416 | { "Stack position", "tibia.coords.stackpos", 2417 | FT_UINT8, BASE_DEC, 2418 | NULL, 0x0, 2419 | NULL, HFILL } 2420 | }, 2421 | #if 0 2422 | { &hf_tibia_item, 2423 | { "Item ID", "tibia.item", 2424 | FT_UINT16, BASE_DEC, 2425 | NULL, 0x0, 2426 | NULL, HFILL } 2427 | }, 2428 | #endif 2429 | { &hf_tibia_container, 2430 | { "Container index", "tibia.container", 2431 | FT_UINT8, BASE_DEC, 2432 | NULL, 0x0, 2433 | NULL, HFILL } 2434 | }, 2435 | { &hf_tibia_container_icon, 2436 | { "Container icon", "tibia.container.icon", 2437 | FT_UINT8, BASE_DEC, 2438 | NULL, 0x0, 2439 | NULL, HFILL } 2440 | }, 2441 | { &hf_tibia_container_slot, 2442 | { "Container slot", "tibia.container.slot", 2443 | FT_UINT8, BASE_DEC, 2444 | NULL, 0x0, 2445 | NULL, HFILL } 2446 | }, 2447 | { &hf_tibia_container_slots, 2448 | { "Container slots", "tibia.container.slots", 2449 | FT_UINT8, BASE_DEC, 2450 | NULL, 0x0, 2451 | NULL, HFILL } 2452 | }, 2453 | { &hf_tibia_inventory, 2454 | { "Inventory slot", "tibia.inventory", 2455 | FT_UINT16, BASE_DEC, 2456 | NULL, 0x0, 2457 | NULL, HFILL } 2458 | }, 2459 | { &hf_tibia_vip, 2460 | { "VIP GUID", "tibia.vip", 2461 | FT_UINT32, BASE_HEX, NULL, 0x0, 2462 | NULL, HFILL } 2463 | }, 2464 | { &hf_tibia_vip_online, 2465 | { "Online", "tibia.vip", 2466 | FT_BOOLEAN, 8, 2467 | NULL, 0x1, 2468 | NULL, HFILL } 2469 | }, 2470 | { &hf_tibia_player, 2471 | { "Player name", "tibia.player", 2472 | FT_UINT_STRING, BASE_NONE, 2473 | NULL, 0x0, 2474 | NULL, HFILL } 2475 | }, 2476 | { &hf_tibia_creature, 2477 | { "Creature", "tibia.creature", 2478 | FT_UINT32, BASE_HEX, 2479 | NULL, 0x0, 2480 | NULL, HFILL } 2481 | }, 2482 | { &hf_tibia_creature_health, 2483 | { "Creature", "tibia.creature.health", 2484 | FT_UINT8, BASE_DEC|BASE_UNIT_STRING, 2485 | &units_percent, 0x0, 2486 | NULL, HFILL } 2487 | }, 2488 | { &hf_tibia_window, 2489 | { "Window", "tibia.window", 2490 | FT_UINT32, BASE_HEX, 2491 | NULL, 0x0, 2492 | NULL, HFILL } 2493 | }, 2494 | { &hf_tibia_window_icon, 2495 | { "Window Icon", "tibia.window.icon", 2496 | FT_UINT8, BASE_HEX, 2497 | NULL, 0x0, 2498 | NULL, HFILL } 2499 | }, 2500 | { &hf_tibia_window_textlen, 2501 | { "Window Text Length", "tibia.window.text.len", 2502 | FT_UINT8, BASE_DEC, 2503 | NULL, 0x0, 2504 | NULL, HFILL } 2505 | }, 2506 | { &hf_tibia_window_text, 2507 | { "Window Text", "tibia.window.text", 2508 | FT_UINT_STRING, BASE_NONE, 2509 | NULL, 0x0, 2510 | NULL, HFILL } 2511 | }, 2512 | { &hf_tibia_squarecolor, 2513 | { "Square Color", "tibia.creature.square", 2514 | FT_UINT8, BASE_HEX, 2515 | NULL, 0x0, 2516 | NULL, HFILL } 2517 | }, 2518 | { &hf_tibia_light_color, 2519 | { "Light Color", "tibia.light.color", 2520 | FT_UINT8, BASE_HEX, 2521 | NULL, 0x0, 2522 | NULL, HFILL } 2523 | }, 2524 | { &hf_tibia_light_level, 2525 | { "Light Level", "tibia.light.level", 2526 | FT_UINT8, BASE_DEC, 2527 | NULL, 0x0, 2528 | NULL, HFILL } 2529 | }, 2530 | { &hf_tibia_magic_effect_id, 2531 | { "Magic Effect", "tibia.magic_effect", 2532 | FT_UINT8, BASE_HEX, 2533 | NULL, 0x0, 2534 | NULL, HFILL } 2535 | }, 2536 | { &hf_tibia_animated_text_color, 2537 | { "Text Color", "tibia.animated_text.color", 2538 | FT_UINT8, BASE_HEX, 2539 | NULL, 0x0, 2540 | NULL, HFILL } 2541 | }, 2542 | { &hf_tibia_animated_text, 2543 | { "Text", "tibia.animated_text", 2544 | FT_UINT16, BASE_HEX, 2545 | NULL, 0x0, 2546 | NULL, HFILL } 2547 | }, 2548 | { &hf_tibia_textmsg_class, 2549 | { "Text Message Class", "tibia.textmsg.class", 2550 | FT_UINT8, BASE_HEX, 2551 | NULL, 0x0, 2552 | NULL, HFILL } 2553 | }, 2554 | { &hf_tibia_textmsg, 2555 | { "Text", "tibia.textmsg", 2556 | FT_UINT_STRING, BASE_NONE, 2557 | NULL, 0x0, 2558 | NULL, HFILL } 2559 | }, 2560 | { &hf_tibia_projectile, 2561 | { "Projectile", "tibia.projectile", 2562 | FT_UINT32, BASE_HEX, 2563 | NULL, 0x0, 2564 | NULL, HFILL } 2565 | }, 2566 | { &hf_tibia_walk_dir, 2567 | { "Walk Direction", "tibia.walk_dir", 2568 | FT_UINT8, BASE_HEX, 2569 | NULL, 0x0, 2570 | NULL, HFILL } 2571 | }, 2572 | }; 2573 | 2574 | static uat_field_t rsakeylist_uats_flds[] = { 2575 | UAT_FLD_CSTRING_OTHER(rsakeylist_uats, ipaddr, "IP address", rsakeys_uat_fld_ip_chk_cb, "IPv4 address"), 2576 | UAT_FLD_CSTRING_OTHER(rsakeylist_uats, port, "Port", rsakeys_uat_fld_port_chk_cb, "Port Number"), 2577 | UAT_FLD_FILENAME_OTHER(rsakeylist_uats, keyfile, "Key File", rsakeys_uat_fld_fileopen_chk_cb, "Private keyfile."), 2578 | UAT_FLD_CSTRING_OTHER(rsakeylist_uats, password,"Password", rsakeys_uat_fld_password_chk_cb, "Password (for keyfile)"), 2579 | UAT_END_FIELDS 2580 | }; 2581 | 2582 | static uat_field_t xteakeylist_uats_flds[] = { 2583 | UAT_FLD_DEC(xteakeylist_uats, framenum, "Frame Number", "XTEA key"), 2584 | UAT_FLD_CSTRING_OTHER(xteakeylist_uats, key, "XTEA Key", xteakeys_uat_fld_key_chk_cb, "Symmetric (XTEA) key"), 2585 | UAT_END_FIELDS 2586 | }; 2587 | 2588 | /* Setup protocol subtree array */ 2589 | static gint *ett[] = { 2590 | &ett_tibia, 2591 | &ett_command, 2592 | &ett_file_versions, 2593 | &ett_client_info, 2594 | &ett_locale, 2595 | &ett_cpu, 2596 | &ett_resolution, 2597 | &ett_charlist, 2598 | &ett_char, 2599 | &ett_worldlist, 2600 | &ett_world, 2601 | &ett_coords, 2602 | &ett_char_cond, 2603 | }; 2604 | 2605 | static ei_register_info ei[] = { 2606 | { &ei_xtea_len_toobig, 2607 | { "tibia.error.xtea.length.toobig", PI_DECRYPTION, PI_ERROR, 2608 | "XTEA-encrypted length exceeds packet", EXPFILL } 2609 | }, 2610 | { &ei_adler32_checksum_bad, { "tibia.error.checksum_bad", PI_CHECKSUM, PI_ERROR, 2611 | "Bad checksum", EXPFILL } 2612 | }, 2613 | { &ei_rsa_plaintext_no_leading_zero, 2614 | { "tibia.error.rsa", PI_DECRYPTION, PI_ERROR, 2615 | "First byte after RSA decryption must be zero", EXPFILL } 2616 | }, 2617 | { &ei_rsa_ciphertext_too_short, 2618 | { "tibia.error.rsa.length.tooshort", PI_DECRYPTION, PI_ERROR, 2619 | "RSA-encrypted data is at least 128 byte long", EXPFILL } 2620 | }, 2621 | { &ei_rsa_decrypt_failed, 2622 | { "tibia.error.rsa.failed", PI_DECRYPTION, PI_ERROR, 2623 | "Decrypting RSA block failed", EXPFILL } 2624 | }, 2625 | }; 2626 | 2627 | proto_tibia = proto_register_protocol ( 2628 | "Tibia Protocol", /* name */ 2629 | "Tibia", /* short name */ 2630 | "tibia" /* abbrev */ 2631 | ); 2632 | proto_register_field_array(proto_tibia, hf, array_length(hf)); 2633 | proto_register_subtree_array(ett, array_length(ett)); 2634 | 2635 | expert_module_t *expert_tibia = expert_register_protocol(proto_tibia); 2636 | expert_register_field_array (expert_tibia, ei, array_length (ei)); 2637 | 2638 | module_t *tibia_module = prefs_register_protocol(proto_tibia, proto_reg_handoff_tibia); 2639 | 2640 | prefs_register_bool_preference(tibia_module, "try_otserv_key", "Try OTServ's RSA key", 2641 | "Try the default RSA key in use by nearly all Open Tibia servers", &try_otserv_key); 2642 | 2643 | prefs_register_bool_preference(tibia_module, "show_char_name", "Show character name for each packet", 2644 | "Shows active character for every packet", &show_char_name); 2645 | prefs_register_bool_preference(tibia_module, "show_acc_info", "Show account info for each packet", 2646 | "Shows account name/password or session key for every packet", &show_acc_info); 2647 | prefs_register_bool_preference(tibia_module, "show_xtea_key", "Show symmetric key used for each packet", 2648 | "Shows which XTEA key was applied for a packet", &show_xtea_key); 2649 | prefs_register_bool_preference(tibia_module, "dissect_game_commands", "Attempt dissection of game packet commands", 2650 | "Only decrypt packets and dissect login packets. Pass game commands to the data dissector", &dissect_game_commands); 2651 | prefs_register_bool_preference(tibia_module, "reassemble_tcp_segments", 2652 | "Reassemble Tibia packets spanning multiple TCP segments", 2653 | "Whether the Tibia dissector should reassemble packets spanning multiple TCP segments." 2654 | " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.", 2655 | &reassemble_tcp_segments); 2656 | 2657 | 2658 | rsakeys = g_hash_table_new_full(rsakey_hash, rsakey_equal, rsakey_free, NULL); 2659 | 2660 | rsakeys_uat = uat_new("RSA Keys", 2661 | sizeof(struct rsakeys_assoc), 2662 | "tibia_rsa_keys", /* filename */ 2663 | TRUE, /* from_profile */ 2664 | &rsakeylist_uats, /* data_ptr */ 2665 | &nrsakeys, /* numitems_ptr */ 2666 | UAT_AFFECTS_DISSECTION, 2667 | NULL, 2668 | rsakeys_copy_cb, 2669 | NULL, 2670 | rsakeys_free_cb, 2671 | rsa_parse_uat, 2672 | NULL, 2673 | rsakeylist_uats_flds); 2674 | prefs_register_uat_preference(tibia_module, "rsakey_table", 2675 | "RSA keys list", 2676 | "A table of RSA keys for decrypting protocols newer than 7.61", 2677 | rsakeys_uat 2678 | ); 2679 | 2680 | xteakeys = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, g_free); 2681 | 2682 | xteakeys_uat = uat_new("XTEA Keys", 2683 | sizeof(struct xteakeys_assoc), 2684 | "tibia_xtea_keys", /* filename */ 2685 | TRUE, /* from_profile */ 2686 | &xteakeylist_uats, /* data_ptr */ 2687 | &nxteakeys, /* numitems_ptr */ 2688 | UAT_AFFECTS_DISSECTION, 2689 | NULL, 2690 | xteakeys_copy_cb, 2691 | NULL, 2692 | xteakeys_free_cb, 2693 | xtea_parse_uat, 2694 | NULL, 2695 | xteakeylist_uats_flds); 2696 | prefs_register_uat_preference(tibia_module, "xteakey_table", 2697 | "XTEA keys list", 2698 | "A table of XTEA keys for decrypting protocols newer than 7.61", 2699 | xteakeys_uat 2700 | ); 2701 | 2702 | 2703 | /* TODO best way to store this in source? */ 2704 | const char sexp[] = 2705 | "(private-key (rsa" 2706 | "(n #9b646903b45b07ac956568d87353bd7165139dd7940703b03e6dd079399661b4a837aa60561d7ccb9452fa0080594909882ab5bca58a1a1b35f8b1059b72b1212611c6152ad3dbb3cfbee7adc142a75d3d75971509c321c5c24a5bd51fd460f01b4e15beb0de1930528a5d3f15c1e3cbf5c401d6777e10acaab33dbe8d5b7ff5#)" 2707 | "(e #010001#)" 2708 | "(d #428bd3b5346daf71a761106f71a43102f8c857d6549c54660bb6378b52b0261399de8ce648bac410e2ea4e0a1ced1fac2756331220ca6db7ad7b5d440b7828865856e7aa6d8f45837feee9b4a3a0aa21322a1e2ab75b1825e786cf81a28a8a09a1e28519db64ff9baf311e850c2bfa1fb7b08a056cc337f7df443761aefe8d81#)" 2709 | "(p #91b37307abe12c05a1b78754746cda444177a784b035cbb96c945affdc022d21da4bd25a4eae259638153e9d73c97c89092096a459e5d16bcadd07fa9d504885#)" 2710 | "(q #0111071b206bafb9c7a2287d7c8d17a42e32abee88dfe9520692b5439d9675817ff4f8c94a4abcd4b5f88e220f3a8658e39247a46c6983d85618fd891001a0acb1#)" 2711 | "(u #6b21cd5e373fe462a22061b44a41fd01738a3892e0bd8728dbb5b5d86e7675235a469fea3266412fe9a659f486144c1e593d56eb3f6cfc7b2edb83ba8e95403a#)" 2712 | "))"; 2713 | 2714 | gcry_error_t err = gcry_sexp_new(&otserv_key, sexp, 0, 1); 2715 | if (err) 2716 | report_failure("Loading OTServ RSA key failed: %s/%s\n", gcry_strerror(err), gcry_strsource(err)); 2717 | } 2718 | 2719 | static guint 2720 | get_dissect_tibia_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_) 2721 | { 2722 | return tvb_get_letohs(tvb, offset) + sizeof(guint16); 2723 | } 2724 | 2725 | static int 2726 | dissect_tibia_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) 2727 | { 2728 | static guint32 packet_num, fragment_num; 2729 | 2730 | if (!packet_num) packet_num = pinfo->num; 2731 | if (packet_num != pinfo->num) { 2732 | fragment_num = 0; 2733 | packet_num = pinfo->num; 2734 | } 2735 | 2736 | fragment_num++; 2737 | 2738 | 2739 | tcp_dissect_pdus(tvb, pinfo, tree, reassemble_tcp_segments, 2, 2740 | get_dissect_tibia_len, dissect_tibia, GUINT_TO_POINTER(fragment_num)); 2741 | return tvb_reported_length(tvb); 2742 | } 2743 | 2744 | void 2745 | proto_reg_handoff_tibia(void) 2746 | { 2747 | dissector_handle_t tibia_handle = create_dissector_handle(dissect_tibia_tcp, proto_tibia); 2748 | 2749 | dissector_add_uint_range_with_preference("tcp.port", TIBIA_DEFAULT_TCP_PORT_RANGE, tibia_handle); 2750 | } 2751 | 2752 | 2753 | /* 2754 | * Editor modelines - http://www.wireshark.org/tools/modelines.html 2755 | * 2756 | * Local variables: 2757 | * c-basic-offset: 4 2758 | * tab-width: 8 2759 | * indent-tabs-mode: nil 2760 | * End: 2761 | * 2762 | * vi: set shiftwidth=4 tabstop=8 expandtab: 2763 | * :indentSize=4:tabSize=8:noTabs=true: 2764 | */ 2765 | -------------------------------------------------------------------------------- /plugin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Do not modify this file. Changes will be overwritten. 3 | * 4 | * Generated automatically from ../../tools/make-dissector-reg.py. 5 | */ 6 | 7 | #include "config.h" 8 | 9 | #include 10 | 11 | #include "moduleinfo.h" 12 | 13 | /* plugins are DLLs */ 14 | #define WS_BUILD_DLL 15 | #include "ws_symbol_export.h" 16 | 17 | #ifndef ENABLE_STATIC 18 | WS_DLL_PUBLIC_DEF void plugin_register (void); 19 | WS_DLL_PUBLIC_DEF const gchar version[] = VERSION; 20 | 21 | extern void proto_register_tibia(void); 22 | 23 | /* Start the functions we need for the plugin stuff */ 24 | 25 | WS_DLL_PUBLIC_DEF void 26 | plugin_register (void) 27 | { 28 | proto_register_tibia(); 29 | } 30 | 31 | extern void proto_reg_handoff_tibia(void); 32 | 33 | WS_DLL_PUBLIC_DEF void plugin_reg_handoff(void); 34 | 35 | WS_DLL_PUBLIC_DEF void 36 | plugin_reg_handoff(void) 37 | { 38 | proto_reg_handoff_tibia(); 39 | } 40 | #endif 41 | -------------------------------------------------------------------------------- /plugin.rc.in: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a3f/Tibia-Wireshark-Plugin/41b7b9c743a8394b822c5f33532e40c22b3df001/plugin.rc.in -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a3f/Tibia-Wireshark-Plugin/41b7b9c743a8394b822c5f33532e40c22b3df001/screenshot.png --------------------------------------------------------------------------------